{ "components": { "schemas": { "AcmeOrderResponse": { "properties": { "authorizations": {}, "certificate_url": { "type": [ "string", "null" ] }, "challenge_validation": { "oneOf": [ { "$ref": "#/components/schemas/ChallengeValidationStatus", "description": "Live challenge validation status fetched from Let's Encrypt" }, { "type": "null" } ] }, "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" }, "ActiveVisitorCountResponse": { "properties": { "active_visitors": { "format": "int64", "type": "integer" }, "window_minutes": { "format": "int32", "type": "integer" } }, "required": [ "active_visitors", "window_minutes" ], "type": "object" }, "ActiveVisitorsQuery": { "description": "Query parameters for active visitors endpoint", "properties": { "deployment_id": { "format": "int32", "type": [ "integer", "null" ] }, "environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "project_id": { "format": "int32", "type": "integer" }, "window_minutes": { "format": "int32", "type": [ "integer", "null" ] } }, "required": [ "project_id" ], "type": "object" }, "ActiveVisitorsResponse": { "properties": { "count": { "format": "int64", "type": "integer" }, "visitors": { "items": { "$ref": "#/components/schemas/ActiveVisitor" }, "type": "array" }, "window_minutes": { "format": "int32", "type": "integer" } }, "required": [ "count", "visitors", "window_minutes" ], "type": "object" }, "ActivityCategory": { "properties": { "description": { "type": "string" }, "name": { "type": "string" } }, "required": [ "name", "description" ], "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" }, "ActivityEvidence": { "properties": { "event": { "type": "string" }, "path": { "type": "string" }, "properties": { "items": { "$ref": "#/components/schemas/ActivityProperty" }, "type": "array" }, "reference": { "description": "Local to this report, not a database event ID.", "format": "int32", "minimum": 0, "type": "integer" }, "timestamp": { "format": "date-time", "type": "string" }, "title": { "type": [ "string", "null" ] } }, "required": [ "reference", "timestamp", "path", "event", "properties" ], "type": "object" }, "ActivityGoal": { "additionalProperties": false, "properties": { "goal": { "type": "string" }, "missing_signals": { "type": "string" }, "rationale": { "type": "string" }, "title": { "type": "string" } }, "required": [ "title", "goal", "rationale", "missing_signals" ], "type": "object" }, "ActivityGoals": { "properties": { "goals": { "items": { "$ref": "#/components/schemas/ActivityGoal" }, "type": "array" }, "model": { "type": "string" }, "pages_read": { "items": { "type": "string" }, "type": "array" } }, "required": [ "goals", "pages_read", "model" ], "type": "object" }, "ActivityGoalsRequest": { "properties": { "environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "share_with_ai": { "type": "boolean" }, "url": { "type": "string" } }, "required": [ "url", "share_with_ai" ], "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" }, "ActivityPreview": { "properties": { "report": { "$ref": "#/components/schemas/ActivityReport" }, "settings": { "$ref": "#/components/schemas/ActivitySettings" } }, "required": [ "settings", "report" ], "type": "object" }, "ActivityPreviewRequest": { "description": "An unsaved onboarding preview. Sharing is explicit and scheduling is never inferred.", "properties": { "environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "goal": { "type": "string" }, "min_page_paths": { "format": "int32", "minimum": 0, "type": "integer" }, "min_sessions": { "format": "int32", "minimum": 0, "type": "integer" }, "property_keys": { "items": { "type": "string" }, "type": "array" }, "share_activity_with_ai": { "type": "boolean" }, "source_domain": { "type": [ "string", "null" ] }, "source_url": { "type": [ "string", "null" ] } }, "required": [ "goal", "share_activity_with_ai" ], "type": "object" }, "ActivityProperty": { "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "type": "object" }, "ActivityReport": { "properties": { "categories": { "items": { "$ref": "#/components/schemas/ActivityCategory" }, "type": "array" }, "completed_at": { "format": "date-time", "type": "string" }, "environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "events_considered": { "minimum": 0, "type": "integer" }, "model": { "type": [ "string", "null" ] }, "sampled": { "type": "boolean" }, "settings_revision": { "format": "int32", "type": "integer" }, "skipped_low_activity": { "minimum": 0, "type": "integer" }, "skipped_unchanged": { "minimum": 0, "type": "integer" }, "started_at": { "format": "date-time", "type": "string" }, "summary": { "type": "string" }, "visitors": { "items": { "$ref": "#/components/schemas/VisitorActivityAssessment" }, "type": "array" }, "window_end": { "format": "date-time", "type": "string" }, "window_start": { "format": "date-time", "type": "string" } }, "required": [ "started_at", "completed_at", "window_start", "window_end", "settings_revision", "categories", "summary", "sampled", "events_considered", "visitors" ], "type": "object" }, "ActivityRunSummary": { "properties": { "analyzed_visitors": { "minimum": 0, "type": "integer" }, "completed_at": { "format": "date-time", "type": "string" }, "environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "error": { "type": [ "string", "null" ] }, "model": { "type": [ "string", "null" ] }, "skipped_low_activity": { "minimum": 0, "type": "integer" }, "skipped_unchanged": { "minimum": 0, "type": "integer" }, "skipped_visitors": { "minimum": 0, "type": "integer" }, "started_at": { "format": "date-time", "type": "string" }, "status": { "type": "string" }, "trigger": { "type": "string" } }, "required": [ "trigger", "status", "started_at", "completed_at", "analyzed_visitors", "skipped_visitors", "skipped_low_activity", "skipped_unchanged" ], "type": "object" }, "ActivitySettings": { "properties": { "application_context": { "type": "string" }, "categories": { "items": { "$ref": "#/components/schemas/ActivityCategory" }, "type": "array" }, "daily_enabled": { "type": "boolean" }, "environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "goal_title": { "description": "Short operator-facing label for the selected analysis goal.", "type": [ "string", "null" ] }, "min_page_paths": { "format": "int32", "minimum": 0, "type": "integer" }, "min_sessions": { "format": "int32", "minimum": 0, "type": "integer" }, "property_keys": { "description": "Only these event-property keys may be sent to the provider.", "items": { "type": "string" }, "type": "array" }, "share_activity_with_ai": { "description": "Explicit permission to send the selected analytics fields to the configured AI provider.", "type": "boolean" }, "source_domain": { "type": [ "string", "null" ] }, "source_url": { "type": [ "string", "null" ] } }, "required": [ "application_context", "categories", "property_keys", "daily_enabled", "share_activity_with_ai" ], "type": "object" }, "ActivityStatus": { "properties": { "ai_model": { "type": [ "string", "null" ] }, "ai_provider": { "type": [ "string", "null" ] }, "configured": { "type": "boolean" }, "has_recent_activity": { "description": "Whether tracked non-crawler visitor events exist in the previous 24 hours.", "type": "boolean" }, "last_error": { "type": [ "string", "null" ] }, "next_run_at": { "format": "date-time", "type": [ "string", "null" ] }, "recent_runs": { "items": { "$ref": "#/components/schemas/ActivityRunSummary" }, "type": "array" }, "report": { "oneOf": [ { "$ref": "#/components/schemas/ActivityReport" }, { "type": "null" } ] }, "running": { "type": "boolean" }, "selected_environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "settings": { "$ref": "#/components/schemas/ActivitySettings" }, "settings_revision": { "format": "int32", "type": "integer" }, "setup_url": { "type": "string" } }, "required": [ "has_recent_activity", "configured", "setup_url", "settings", "settings_revision", "running", "recent_runs" ], "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": { "batchId": { "description": "Client-generated id, stable across retries of the same batch. When\npresent the append is idempotent; omitted, delivery is at-least-once.", "type": [ "string", "null" ] }, "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" ] }, "proxied_by_default": { "type": "boolean" }, "sync_generated_records": { "description": "Opt in to reconciling generated hostnames into this domain's DNS zone.", "type": "boolean" } }, "required": [ "domain" ], "type": "object" }, "AddProviderModelRequest": { "properties": { "display_name": { "type": [ "string", "null" ] }, "model_id": { "type": "string" } }, "required": [ "model_id" ], "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" }, "AdoptDeliveryRecord": { "properties": { "name": { "type": "string" }, "record_type": { "$ref": "#/components/schemas/DnsRecordType" } }, "required": [ "name", "record_type" ], "type": "object" }, "AdoptHostnameRecord": { "description": "A conflicting record the user confirmed the generated-hostname sync may\nadopt: stamp it as the sync's own record, then point it at the value the\nsync writes. The apply refuses it when the conflict changed after the\npreview, so only the record the user reviewed is ever adopted.", "properties": { "name": { "description": "The conflict's `name`.", "example": "pr-12.preview.example.com", "type": "string" }, "record_type": { "description": "The conflict's `record_type`.", "example": "A", "type": "string" }, "revision": { "description": "The conflict's `revision`, from the preview the user reviewed.", "type": "string" } }, "required": [ "name", "record_type", "revision" ], "type": "object" }, "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": [ { "$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." }, { "type": "null" } ] }, "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": { "allowed_node_ids": { "default": null, "description": "Nodes allowed to run sandboxes (ADR-048). `None` (the default) =\nevery node, including the control plane. `Some(ids)` = only those\nnodes; the control plane is id `0`. `Some([])` disables sandbox\ncreation. Owned by `PUT /sandboxes/placement`; the generic settings\nupdate preserves the stored value.", "items": { "format": "int32", "type": "integer" }, "type": [ "array", "null" ] }, "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" }, "AggregateResponse": { "properties": { "rows": { "items": { "$ref": "#/components/schemas/AggregateRow" }, "type": "array" } }, "required": [ "rows" ], "type": "object" }, "AggregateRow": { "description": "One row of an aggregation: the group values (in `group_by` order) and\nthe metric.", "properties": { "keys": { "items": { "type": "string" }, "type": "array" }, "lines": { "description": "Lines that contributed (always populated; equals `value` for\n`Count`).", "format": "int64", "type": "integer" }, "value": { "format": "double", "type": "number" } }, "required": [ "keys", "value", "lines" ], "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" }, "AiModelOptionDto": { "properties": { "default_thinking_option_id": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "name": { "type": "string" }, "thinking_options": { "items": { "$ref": "#/components/schemas/AiSelectOptionDto" }, "type": "array" }, "tool_thinking_options": { "description": "Model-specific reasoning options valid while project-chat function\ntools are attached. Omitted when the normal options also apply.", "items": { "$ref": "#/components/schemas/AiSelectOptionDto" }, "type": [ "array", "null" ] } }, "required": [ "id", "name", "thinking_options" ], "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" }, "AiProviderStatusResponse": { "description": "Current API-gateway availability for this instance.\n\nThe `configured` field drives the UI onboarding state: when `false` the UI\nmust show _exactly what is missing_ (`reason`) and _where to fix it_\n(`setup_path`), not hide the feature.", "properties": { "available_providers": { "description": "Gateway providers available to API-backed chat and summaries. Credential\nsource is descriptive metadata only and never contains secret values.", "items": { "$ref": "#/components/schemas/AvailableAiProviderDto" }, "type": "array" }, "configured": { "description": "Whether the active provider is ready to serve requests.", "type": "boolean" }, "gateway_available": { "description": "Whether at least one active BYOK provider key exists.", "type": "boolean" }, "interactive_bridge_status": { "description": "Health of normalized mid-turn user interactions, or `null` when the\nactive adapter does not advertise them. Kept for API compatibility.", "type": [ "string", "null" ] }, "reason": { "description": "Human-readable explanation of why `configured` is `false`.", "type": [ "string", "null" ] }, "setup_path": { "description": "Console path the operator should visit to fix the missing configuration.", "type": [ "string", "null" ] }, "summary_preference": { "$ref": "#/components/schemas/AiSummaryPreferenceDto", "description": "Instance-wide defaults inherited by all server-authored AI summaries." }, "supports_interactive_tools": { "description": "Whether the active adapter's normalized realtime contract exposes tool\nevents. Kept under the legacy field name for API compatibility.", "type": "boolean" } }, "required": [ "configured", "gateway_available", "available_providers", "supports_interactive_tools", "summary_preference" ], "type": "object" }, "AiSelectOptionDto": { "properties": { "description": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ], "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 (`1xx`/`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" }, "AiSummaryPreferenceDto": { "properties": { "model": { "description": "`null` uses the selected provider's default model.", "type": [ "string", "null" ] }, "provider_id": { "description": "Normalized gateway route (`gateway_key:{id}`). `null` inherits the\nactive gateway key.", "type": [ "string", "null" ] }, "thinking_level": { "description": "`null` uses the selected model's default reasoning depth.", "type": [ "string", "null" ] } }, "type": "object" }, "AiWorkspaceFileLimitsSettings": { "description": "Runtime limits for workspace file transfer and browser previews.\n\nThe HTTP layer additionally enforces absolute ceilings so a malformed or\nlegacy settings row cannot turn a configurable limit into unbounded control\nplane memory use.", "properties": { "max_download_size_mb": { "default": 32, "example": 32, "format": "int32", "maximum": 32, "minimum": 1, "type": "integer" }, "max_file_size_mb": { "default": 16, "example": 16, "format": "int32", "maximum": 32, "minimum": 1, "type": "integer" }, "max_files_per_upload": { "default": 32, "example": 32, "format": "int32", "maximum": 100, "minimum": 1, "type": "integer" }, "max_image_preview_size_mb": { "default": 8, "example": 8, "format": "int32", "maximum": 16, "minimum": 1, "type": "integer" }, "max_text_preview_kb": { "default": 256, "example": 256, "format": "int32", "maximum": 1024, "minimum": 1, "type": "integer" }, "max_upload_size_mb": { "default": 32, "example": 32, "format": "int32", "maximum": 32, "minimum": 1, "type": "integer" }, "max_workspace_entries": { "default": 5000, "example": 5000, "format": "int32", "maximum": 50000, "minimum": 1, "type": "integer" }, "max_workspace_size_mb": { "default": 256, "example": 256, "format": "int32", "maximum": 2048, "minimum": 1, "type": "integer" } }, "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": { "description": "`None` for host/control-plane-wide alarms with no associated project.", "format": "int32", "type": [ "integer", "null" ] }, "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" }, "silenced_until": { "description": "ISO-8601 UTC timestamp this alarm (and future re-fires of the same\ntype/scope) are muted until, if currently silenced. Not cleared when\nthe silence expires — check against the current time, or compare to\n`fired_at` on a *new* alarm of the same scope to know a silence has\nlapsed.", "type": [ "string", "null" ] }, "status": { "type": "string" }, "title": { "type": "string" }, "updated_at": { "description": "ISO-8601 UTC timestamp when the row was last updated.", "type": "string" } }, "required": [ "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" }, "AnalyticsCapability": { "properties": { "backend": { "oneOf": [ { "$ref": "#/components/schemas/LineIndexBackend", "description": "Where the index lives (`clickhouse`, `temps_cloud` or `timescaledb`)\nwhen configured. The TimescaleDB fallback answers the same endpoints\nbut scales with line count on the control-plane database; the\nonboarding copy points at ClickHouse or Temps Cloud for volume." }, { "type": "null" } ] }, "configured": { "description": "`true` when the line index is active and receiving sealed chunks.", "type": "boolean" }, "example": { "description": "What analytics would do here — shown as the example in the\nonboarding state.", "type": "string" }, "forget_backlog": { "description": "Chunks retired (compacted, purged, or expired by retention) whose\nremoval from the line index has not yet been confirmed — durably\nqueued in `log_line_forget_backlog` and drained by `ForgetSweeper`\n(ADR-047 §8a). Non-zero for more than a few sweep intervals (30s,\nsee [`crate::services::FORGET_SWEEP_INTERVAL`]) means the index\nstill holds rows for chunks that no longer exist — over-counted in\nfacets/histograms/aggregates until the sweeper catches up.", "format": "int64", "minimum": 0, "type": "integer" }, "indexed_chunks": { "format": "int64", "minimum": 0, "type": "integer" }, "live_chunks": { "description": "Live chunks in the manifest and how many of them are indexed. Equal\nnumbers mean the index is complete; a gap is the reindexer's queue.", "format": "int64", "minimum": 0, "type": "integer" }, "max_window_days": { "description": "Widest window one analytics query answers on this store, in days.\nThe TimescaleDB store clamps `start_time` to this many days before\n`end_time` so a query can never scan the whole control-plane\ndatabase; ClickHouse stores are unbounded (`None`).", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "reason": { "description": "Exactly what is missing, when `configured` is false.", "type": [ "string", "null" ] }, "setup_path": { "description": "Console route where the operator fixes it.", "type": "string" } }, "required": [ "configured", "setup_path", "example", "live_chunks", "indexed_chunks", "forget_backlog" ], "type": "object" }, "AnalyticsFacet": { "enum": [ "summary", "traffic", "pages", "events", "breakdown", "speed" ], "type": "string" }, "AnalyticsIngestKey": { "description": "An analytics ingest key as returned by the admin API.\n\n`public_key` is present in full on every response — see the module docs.", "properties": { "allowed_origins": { "description": "Exact origins (`scheme://host[:port]`) permitted to use this key from a\nbrowser. `None` or `[]` means any origin. This is a browser-enforced\nconvenience control, not authentication — a non-browser client ignores\n`Origin` entirely.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "created_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": "string" }, "created_by_user_id": { "format": "int32", "type": [ "integer", "null" ] }, "environment_id": { "description": "`None` means the key is scoped to the whole project. An\nenvironment-scoped key additionally attributes ingested data to that\nenvironment's current deployment, when it has one.", "format": "int32", "type": [ "integer", "null" ] }, "event_count": { "format": "int64", "type": "integer" }, "id": { "format": "int32", "type": "integer" }, "is_active": { "type": "boolean" }, "last_used_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": [ "string", "null" ] }, "name": { "description": "Operator-facing label.", "type": "string" }, "project_id": { "format": "int32", "type": "integer" }, "public_key": { "description": "The ingest key itself, `pa_` + 64 hex characters.\n\n**Not a secret.** It is designed to ship in client-side JavaScript and\nis returned unmasked so operators can copy it. See the module docs.", "type": "string" }, "rate_limit_per_minute": { "description": "`None` or `<= 0` means unlimited.", "format": "int32", "type": [ "integer", "null" ] }, "revoked_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": [ "string", "null" ] }, "updated_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": "string" } }, "required": [ "id", "project_id", "name", "public_key", "is_active", "event_count", "created_at", "updated_at" ], "type": "object" }, "AnalyticsProjectOption": { "properties": { "project_id": { "format": "int32", "type": "integer" }, "project_name": { "type": "string" } }, "required": [ "project_id", "project_name" ], "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" }, "ApiCallerEntry": { "description": "A single caller entry in the top-callers breakdown.", "properties": { "client_ip": { "description": "Caller IP address as recorded in proxy_logs.client_ip.", "type": "string" }, "error_rate": { "description": "Error rate for this caller (0.0–1.0).", "format": "double", "type": "number" }, "last_seen": { "description": "Timestamp of the most recent request from this IP in the period.", "format": "date-time", "type": "string" }, "request_count": { "description": "Total request count from this IP in the period.", "format": "int64", "type": "integer" } }, "required": [ "client_ip", "request_count", "error_rate", "last_seen" ], "type": "object" }, "ApiCallersResponse": { "description": "Top callers (by IP) ranked by request count for a given project + time window.", "properties": { "callers": { "description": "Top callers, ordered by request_count descending.", "items": { "$ref": "#/components/schemas/ApiCallerEntry" }, "type": "array" }, "total_callers": { "description": "Total distinct client IPs seen in the period (before the limit).", "format": "int64", "type": "integer" } }, "required": [ "callers", "total_callers" ], "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" }, "ApiRouteEntry": { "description": "A single route entry in the top-routes breakdown.\n\nRoutes are grouped by raw `(method, path)` — no template normalization.\nSee the module-level note on path cardinality.", "properties": { "avg_latency_ms": { "description": "Mean response time in milliseconds for this route.", "format": "double", "type": [ "number", "null" ] }, "error_rate": { "description": "Error rate for this route (0.0–1.0): requests with status >= 400.", "format": "double", "type": "number" }, "method": { "description": "HTTP method (e.g. \"GET\", \"POST\").", "type": "string" }, "path": { "description": "Raw request path (e.g. \"/api/users/123\"). High-cardinality paths with\ndynamic IDs will appear as separate rows until path normalization is\nimplemented.", "type": "string" }, "request_count": { "description": "Total request count for this route in the period.", "format": "int64", "type": "integer" } }, "required": [ "method", "path", "request_count", "error_rate" ], "type": "object" }, "ApiRoutesResponse": { "description": "Top routes by request count for a given project + time window.", "properties": { "routes": { "description": "Top routes, ordered by request_count descending.", "items": { "$ref": "#/components/schemas/ApiRouteEntry" }, "type": "array" }, "total_routes": { "description": "Total distinct (method, path) pairs in the period (before the limit).", "format": "int64", "type": "integer" } }, "required": [ "routes", "total_routes" ], "type": "object" }, "ApiTimeseriesPoint": { "description": "A single time bucket in the API request timeseries.", "properties": { "avg_latency_ms": { "description": "Mean response time in milliseconds. Null when no rows with a recorded\nresponse_time_ms exist in the bucket.", "format": "double", "type": [ "number", "null" ] }, "error_count": { "description": "Number of requests with status >= 400.", "format": "int64", "type": "integer" }, "error_rate": { "description": "Error rate: error_count / request_count (0.0–1.0). Zero when\nrequest_count == 0.", "format": "double", "type": "number" }, "p95_latency_ms": { "description": "p95 response time in milliseconds. Null when insufficient data.", "format": "double", "type": [ "number", "null" ] }, "p99_latency_ms": { "description": "p99 response time in milliseconds. Null when insufficient data.", "format": "double", "type": [ "number", "null" ] }, "request_count": { "description": "Total request count in this bucket.", "format": "int64", "type": "integer" }, "timestamp": { "description": "Bucket start timestamp (ISO 8601 with Z suffix).", "format": "date-time", "type": "string" } }, "required": [ "timestamp", "request_count", "error_count", "error_rate" ], "type": "object" }, "ApiTimeseriesResponse": { "description": "Timeseries of API request volume, error rate, and latency percentiles.", "properties": { "bucket_interval": { "description": "Bucket interval used for time series (e.g. \"1 hour\", \"6 hours\", \"1 day\").", "type": "string" }, "overall_avg_latency_ms": { "description": "Overall mean response time in milliseconds over the full period.", "format": "double", "type": [ "number", "null" ] }, "overall_error_rate": { "description": "Overall error rate over the full period (0.0–1.0).", "format": "double", "type": "number" }, "points": { "description": "Time-bucketed data points ordered ascending by timestamp.", "items": { "$ref": "#/components/schemas/ApiTimeseriesPoint" }, "type": "array" }, "total_errors": { "description": "Aggregate error count (status >= 400) over the full period.", "format": "int64", "type": "integer" }, "total_requests": { "description": "Aggregate request count over the full period.", "format": "int64", "type": "integer" } }, "required": [ "points", "total_requests", "total_errors", "overall_error_rate", "bucket_interval" ], "type": "object" }, "ApiTrafficSummary": { "description": "Structured AI summary of API traffic for a given project + time window.\n\nDerives `JsonSchema` so `complete_typed` can request this shape from the\nconfigured AI provider. All fields are intentionally short — the prompt\nfeeds aggregated stats (not raw log lines) to keep token usage bounded.\n\nWhen AI is not configured or the project has not opted in, the summary\nendpoint returns `null` for this field rather than an error.", "properties": { "anomalies": { "description": "Anomalies or concerns worth investigating (0–3 items). Empty when\ntraffic appears normal.", "items": { "type": "string" }, "type": "array" }, "findings": { "description": "Bullet-point findings (2–4 items). Each finding is a single sentence.", "items": { "type": "string" }, "type": "array" }, "headline": { "description": "One-sentence headline describing the traffic pattern.", "type": "string" }, "recommendation": { "description": "Optional single actionable recommendation.", "type": [ "string", "null" ] } }, "required": [ "headline", "findings", "anomalies" ], "type": "object" }, "ApiTrafficSummaryResponse": { "description": "Response from the AI traffic summary endpoint.", "properties": { "cached": { "description": "Whether this response was served from the backend AI-result cache.", "type": "boolean" }, "enabled": { "description": "Whether the project has `ai_api_traffic_summary_enabled = true`.", "type": "boolean" }, "summary": { "oneOf": [ { "$ref": "#/components/schemas/ApiTrafficSummary", "description": "The AI-generated summary, or `null` when AI is not configured or the\nproject has not opted in (`ai_api_traffic_summary_enabled = false`)." }, { "type": "null" } ] }, "unavailable_reason": { "description": "Why the summary is null when `summary` is None and `enabled` is true:\neither AI is not configured or the call failed/timed out.", "type": [ "string", "null" ] } }, "required": [ "enabled", "cached" ], "type": "object" }, "AppSettings": { "description": "Application settings stored in the database\nAll fields have sensible defaults for easy onboarding", "properties": { "agent_sandbox": { "$ref": "#/components/schemas/AgentSandboxSettings", "default": { "allowed_node_ids": null, "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 } }, "ai_chat_limits": { "$ref": "#/components/schemas/AiChatLimitsSettings", "default": { "turn_timeout_secs": 900 }, "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": { "$ref": "#/components/schemas/AiConfigSettings", "default": { "config_repo": "", "config_repo_branch": "main" } }, "ai_workspace_file_limits": { "$ref": "#/components/schemas/AiWorkspaceFileLimitsSettings", "default": { "max_download_size_mb": 32, "max_file_size_mb": 16, "max_files_per_upload": 32, "max_image_preview_size_mb": 8, "max_text_preview_kb": 256, "max_upload_size_mb": 32, "max_workspace_entries": 5000, "max_workspace_size_mb": 256 }, "description": "Transfer and preview limits for files in persistent AI workspaces.\nThese are runtime settings because operators have different control\nplane memory budgets and commonly work with very different asset sizes." }, "anonymous_telemetry_enabled": { "default": null, "description": "Admin preference for anonymous product telemetry (the events sent to\nthe Temps maintainers by `temps-telemetry`; unrelated to Temps Cloud\nmirroring in `cloud.telemetry_enabled` and to OpenTelemetry ingest).\n\n- `None` (default) — the operator has not chosen; the built-in default\n applies (see `temps_telemetry::DEFAULT_TELEMETRY_ENABLED`).\n- `Some(true)` / `Some(false)` — an admin turned it on/off from\n Settings › Telemetry. Applied at runtime without a restart.\n\nThe `TEMPS_TELEMETRY=0` environment variable is a host-level kill\nswitch that wins over this value unconditionally. The dedicated\n`PATCH /settings/telemetry` endpoint is the only write path: the\ngeneric settings save restores the stored value under the row lock, so\nan older client round-tripping the whole document cannot flip it.", "type": [ "boolean", "null" ] }, "build_limits": { "$ref": "#/components/schemas/BuildLimitsSettings", "default": { "cpu_limit_cores": 0, "max_concurrent": 2, "memory_limit_mb": 0 }, "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)." }, "bunny_new_projects": { "default": false, "description": "Enable Bunny delivery by default only for projects created after this is set.", "type": "boolean" }, "cloud": { "$ref": "#/components/schemas/CloudSettings", "default": { "backend_url": "https://app.temps.sh", "backups_enabled": false, "console_access_enabled": false, "notifications_enabled": false, "telemetry_bulk_anomaly_factor": null, "telemetry_bulk_rate_limit_spans_per_sec": null, "telemetry_enabled": false, "telemetry_outbox_max_bytes": 536870912 }, "description": "Managed control-plane connection. Credentials are deliberately not\nstored here; they live in the owner-only cloud-link state file." }, "cloudflare_new_projects": { "default": false, "description": "Enable Cloudflare delivery by default for projects created after this is set.", "type": "boolean" }, "cluster_dns": { "$ref": "#/components/schemas/ClusterDnsSettings", "default": { "enabled": false }, "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." }, "connection_limits": { "$ref": "#/components/schemas/ConnectionLimitSettings", "default": { "default_max_concurrent_connections": 0 }, "description": "Per-upstream concurrent-connection cap applied by the proxy to\ncustomer app traffic. `0` (the default) is unlimited. See issue #646." }, "console_force_https": { "default": null, "description": "Whether plain-HTTP requests to the console host (`external_url`) are\nredirected to HTTPS. Same tri-state contract as an environment's\n`force_https`:\n\n- `None` (default) — inherit the per-host heuristic: redirect only once\n the console hostname has actually completed TLS provisioning. An\n HTTP-only install, and an install whose TLS is terminated upstream,\n are both left alone.\n- `Some(true)` — always redirect. For operators who terminate TLS at\n Temps but have not provisioned the cert through Temps.\n- `Some(false)` — never redirect, even once a certificate exists.\n\nDeliberately operator-set rather than inferred. Temps cannot tell\n\"HTTPS terminated by an upstream CDN\" apart from \"plain HTTP\" — both\narrive as a plaintext connection, and `X-Forwarded-Proto` is not\ntrustworthy from an arbitrary peer — so inferring `true` from an\n`https://` `external_url` would 301 a CDN-fronted console into an\ninfinite redirect loop with no way out but the global kill switch.", "type": [ "boolean", "null" ] }, "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": { "$ref": "#/components/schemas/ContainerLogSettings", "default": { "cache_mb": 2048, "head_buffer_mb": 8, "max_file": 3, "max_size": "50m", "service_max_file": 3, "service_max_size": "20m" } }, "disk_space_alert": { "$ref": "#/components/schemas/DiskSpaceAlertSettings", "default": { "check_interval_seconds": 300, "enabled": true, "monitor_path": null, "threshold_percent": 80 } }, "dns_provider": { "$ref": "#/components/schemas/DnsProviderSettings", "default": { "cloudflare_api_key": null, "provider": "manual" } }, "docker_registry": { "$ref": "#/components/schemas/DockerRegistrySettings", "default": { "ca_certificate": null, "enabled": false, "password": null, "registry_url": null, "tls_verify": true, "username": null } }, "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" ] }, "geo": { "$ref": "#/components/schemas/GeoSettings", "default": { "build_epoch": null, "last_check_at": null, "last_check_status": null, "last_error": null, "last_refreshed_at": null, "maxmind_license_key_encrypted": null, "refresh_interval_hours": null, "source": null, "stale_lookup_days": null }, "description": "Geolocation database refresh policy, MaxMind credential (encrypted at\nrest), and the self-recorded freshness metadata of the last refresh." }, "image_retention": { "$ref": "#/components/schemas/ImageRetentionSettings", "default": { "default_hours": 336, "enabled": true }, "description": "Retention policy for locally-built deployment images. Modeled as a\nsettings row (not an env var) per CLAUDE.md so an operator can change\nthe system-wide default at runtime without restarting the binary.\nIndividual projects override it via `projects.image_retention_hours`." }, "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": { "$ref": "#/components/schemas/LetsEncryptSettings", "default": { "email": null, "environment": "production" } }, "mcp_server": { "$ref": "#/components/schemas/McpServerSettings", "default": { "enabled": false }, "description": "MCP server settings (ADR-039). Off by default — enable via the Settings\nUI to expose the MCP endpoint to the Temps CLI wizard." }, "monitoring": { "$ref": "#/components/schemas/MonitoringSettings", "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" }, "description": "Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows." }, "multi_node": { "$ref": "#/components/schemas/MultiNodeSettings", "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_failover_after_secs": 300, "node_memory_alert_percent": 90, "private_address": null, "require_mtls": true } }, "observability_compression": { "$ref": "#/components/schemas/ObservabilityCompressionSettings", "default": { "otel_spans_after_hours": 24, "proxy_logs_after_hours": 24 }, "description": "TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API." }, "observability_retention": { "$ref": "#/components/schemas/ObservabilityRetentionSettings", "default": { "container_logs_days": 30, "otel_logs_days": 90, "otel_metrics_days": 90, "otel_spans_days": 90, "proxy_logs_days": 30 }, "description": "Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API." }, "on_demand_tls": { "$ref": "#/components/schemas/OnDemandTlsSettings", "default": { "deployment_url_mode": "http", "enabled": false, "hourly_cap": 10, "max_concurrent": 3, "zone": null } }, "plugin_installation_reporting_enabled": { "default": false, "description": "Share verified external-plugin installation counts with the official\nregistry. Defaults to off; each plugin receives an unlinkable ID.", "type": "boolean" }, "preview_domain": { "default": "localho.st", "type": "string" }, "preview_gateway": { "$ref": "#/components/schemas/PreviewGatewaySettings", "default": { "auto_upgrade": true, "container_name": "temps-preview-gateway", "enabled": true, "host_port": 8090, "image": "" }, "description": "Workspace preview gateway settings (single shared container per node).\nOwned by `PATCH /preview-gateway/settings` and\n`POST /preview-gateway/upgrade`, which change the gateway's containers\nto match; the generic settings update preserves the stored value." }, "rate_limiting": { "$ref": "#/components/schemas/RateLimitSettings", "default": { "blacklist_ips": [], "enabled": false, "max_requests_per_hour": 1000, "max_requests_per_minute": 60, "whitelist_ips": [] } }, "registry_mirror_prefix": { "default": null, "description": "Prefix applied to Docker Hub base images generated for a build (e.g.\nautopack's `FROM node:22-slim`), turning them into\n`{prefix}/node:22-slim`. Unlike `docker_registry` above — which\nauthenticates pulls to one *named* private registry a user's own image\nreference already points at — this rewrites Temps' own generated,\notherwise-anonymous `docker.io` references, for operators whose\ninternal registry is a path-prefixing reverse proxy rather than a\n`registry-mirrors`-compatible pull-through cache (which needs no\nrewriting at all — see docs/howto/configure-a-docker-registry-mirror).\n`None`/empty (the default) leaves every reference untouched.", "type": [ "string", "null" ] }, "request_timeouts": { "$ref": "#/components/schemas/RequestTimeoutSettings", "default": { "default_http_timeout_seconds": 0, "default_sse_idle_timeout_seconds": 0, "default_websocket_idle_timeout_seconds": 0, "max_request_timeout_seconds": 600 }, "description": "Upstream request/connection timeouts applied by the proxy to customer\napp traffic. Provides a global hard ceiling plus global defaults for\nregular HTTP, SSE, and WebSocket traffic; projects and environments\nmay set a shorter value but never exceed the ceiling here." }, "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": { "$ref": "#/components/schemas/ScreenshotSettings", "default": { "enabled": false, "provider": "local", "url": "" } }, "security_headers": { "$ref": "#/components/schemas/SecurityHeadersSettings", "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" } }, "self_update": { "default": null, "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.\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()`." }, { "type": "null" } ] }, "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" }, "tenant_resource_ceilings": { "$ref": "#/components/schemas/TenantResourceCeilings", "default": { "allow_unlimited_request_timeouts": true, "max_concurrent_connections": 0, "max_memory_limit_mb": 0 }, "description": "Ceilings the operator places on what a *tenant* may configure for\ntheir own project/environment. Entirely unenforced by default, so an\nupgrade never changes what an existing config means." }, "trust_loopback_forwarded_ip": { "default": null, "description": "Allow the proxy to use forwarding headers from a loopback peer for\nclient IP attribution. `None` means an older client did not send the\nfield; the settings handler preserves the stored decision on PUT.\nThis is the sole control surface — there is no CLI/env override.", "type": [ "boolean", "null" ] } }, "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" }, "ai_workspace_file_limits": { "$ref": "#/components/schemas/AiWorkspaceFileLimitsSettings", "description": "Persistent AI workspace file transfer and preview limits." }, "build_limits": { "$ref": "#/components/schemas/BuildLimitsSettings", "description": "Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is." }, "bunny_new_projects": { "type": "boolean" }, "cloud": { "$ref": "#/components/schemas/CloudSettings", "description": "Managed control-plane destination and explicit export consent flags." }, "cloudflare_new_projects": { "description": "Applies Cloudflare delivery only to future projects.", "type": "boolean" }, "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." }, "connection_limits": { "$ref": "#/components/schemas/ConnectionLimitSettings", "description": "Per-upstream concurrent-connection cap applied by the proxy to\ncustomer app traffic. No sensitive content. See issue #646." }, "console_force_https": { "description": "Whether plain-HTTP requests to the console host are redirected to HTTPS.\n`None` inherits the per-host certificate heuristic; `Some(b)` is an\nexplicit operator override. No sensitive content.", "type": [ "boolean", "null" ] }, "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" ] }, "geo": { "$ref": "#/components/schemas/GeoSettingsMasked", "description": "Geolocation refresh policy and freshness, with the MaxMind license key\nreported only as a boolean." }, "image_retention": { "$ref": "#/components/schemas/ImageRetentionSettings", "description": "Deployment-image retention policy. No sensitive content, passed through\nas-is so the settings UI can show and edit the system-wide default." }, "insecure_tls": { "type": "boolean" }, "internal_url": { "type": [ "string", "null" ] }, "letsencrypt": { "$ref": "#/components/schemas/LetsEncryptSettings" }, "mcp_server": { "$ref": "#/components/schemas/McpServerSettings", "description": "MCP (Model Context Protocol) server toggle (ADR-039). No sensitive\ncontent — passed through as-is so the settings UI can show and edit it." }, "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." }, "on_demand_tls": { "$ref": "#/components/schemas/OnDemandTlsSettings", "description": "On-demand (lazy) HTTP-01 TLS issuance (ADR-018). No sensitive content,\npassed through as-is so operators can see whether on-demand\ncertificates are enabled and for which zone." }, "plugin_installation_reporting_enabled": { "description": "Consent for verified external-plugin installation count reporting.", "type": "boolean" }, "preview_domain": { "type": "string" }, "preview_gateway": { "$ref": "#/components/schemas/PreviewGatewaySettingsMasked" }, "proxy_port": { "description": "Port the main Pingora proxy listens on (parsed from `--address`), the\nsame value `ConfigService::proxy_port()` feeds into\n`compute_deployment_url`/`compute_environment_url` when `external_url`\nis unset. The console uses this to preview a project's real\n`{slug}-{env_slug}.{preview_domain}:{port}` URL before it's deployed.", "format": "int32", "minimum": 0, "type": "integer" }, "rate_limiting": { "$ref": "#/components/schemas/RateLimitSettings" }, "registry_mirror_prefix": { "description": "Prefix applied to implicit Docker Hub base images in generated\nDockerfiles (e.g. autopack's `FROM node:22-slim`). No sensitive\ncontent, passed through as-is. `None`/empty disables rewriting.", "type": [ "string", "null" ] }, "request_timeouts": { "$ref": "#/components/schemas/RequestTimeoutSettings", "description": "Upstream request/connection timeouts (hard ceiling + defaults) applied\nby the proxy to customer app traffic. No sensitive content." }, "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" }, "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" }, "tenant_resource_ceilings": { "$ref": "#/components/schemas/TenantResourceCeilings", "description": "Upper bounds a project/environment override may not exceed. No\nsensitive content — this is operator policy the settings UI edits\ndirectly. Unenforced by default." }, "trust_loopback_forwarded_ip": { "description": "Database-backed opt-in; this is the sole control surface for every\nproxy process, including a standalone `temps proxy`.", "type": "boolean" } }, "required": [ "plugin_installation_reporting_enabled", "preview_domain", "cloudflare_new_projects", "bunny_new_projects", "proxy_port", "cloud", "screenshots", "letsencrypt", "dns_provider", "security_headers", "rate_limiting", "trust_loopback_forwarded_ip", "docker_registry", "disk_space_alert", "container_logs", "agent_sandbox", "ai_config", "preview_gateway", "multi_node", "monitoring", "observability_compression", "observability_retention", "geo", "effective_metrics_store", "effective_observability_store", "insecure_tls", "setup_complete", "require_mfa_for_admins", "on_demand_tls", "cluster_dns", "build_limits", "ai_chat_limits", "ai_workspace_file_limits", "request_timeouts", "connection_limits", "tenant_resource_ceilings", "self_update", "image_retention", "mcp_server" ], "type": "object" }, "ApplicationGitConnectionsResponse": { "properties": { "bindings": { "items": { "$ref": "#/components/schemas/GitBindingResponse" }, "type": "array" }, "eligibleRepositories": { "items": { "$ref": "#/components/schemas/EligibleGitRepositoryResponse" }, "type": "array" } }, "required": [ "bindings", "eligibleRepositories" ], "type": "object" }, "ApplicationPreviewLinkResponse": { "properties": { "expires_at": { "format": "int64", "minimum": 0, "type": "integer" }, "url": { "description": "A short-lived authenticated URL. Its fragment carries the grant and\nnever reaches the development server or referrer headers.", "type": "string" } }, "required": [ "url", "expires_at" ], "type": "object" }, "ApplicationProjectDeploymentResponse": { "properties": { "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" ], "type": "object" }, "ApplicationProjectEnvironmentResponse": { "properties": { "deployment_state": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "sleeping": { "type": "boolean" }, "slug": { "type": "string" } }, "required": [ "name", "slug", "sleeping" ], "type": "object" }, "ApplicationProjectResponse": { "properties": { "automatic_deploy": { "type": "boolean" }, "environments": { "items": { "$ref": "#/components/schemas/ApplicationProjectEnvironmentResponse" }, "type": "array" }, "id": { "format": "int32", "type": "integer" }, "is_primary": { "type": "boolean" }, "is_private": { "type": "boolean" }, "last_deployment_at": { "type": [ "string", "null" ] }, "main_branch": { "type": "string" }, "name": { "type": "string" }, "repository": { "type": [ "string", "null" ] }, "slug": { "type": "string" } }, "required": [ "id", "name", "slug", "main_branch", "is_private", "is_primary", "automatic_deploy", "environments" ], "type": "object" }, "ApplicationResponse": { "properties": { "created_at": { "type": "string" }, "description": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "projects": { "items": { "$ref": "#/components/schemas/ApplicationProjectResponse" }, "type": "array" }, "public_id": { "type": "string" }, "status": { "type": "string" }, "updated_at": { "type": "string" } }, "required": [ "public_id", "name", "status", "projects", "created_at", "updated_at" ], "type": "object" }, "ApplicationWorkspaceChangesResponse": { "properties": { "branch": { "type": [ "string", "null" ] }, "changes": { "items": { "$ref": "#/components/schemas/ApplicationWorkspaceFileResponse" }, "type": "array" }, "changes_truncated": { "type": "boolean" }, "clean": { "type": "boolean" }, "files": { "items": { "type": "string" }, "type": "array" }, "files_truncated": { "type": "boolean" }, "head": { "type": [ "string", "null" ] }, "listed_file_count": { "description": "Number of file paths discovered within the server-side safety cap.", "minimum": 0, "type": "integer" }, "next_cursor": { "description": "Opaque position for the next bounded page, when another page exists.", "minimum": 0, "type": [ "integer", "null" ] }, "truncated": { "type": "boolean" } }, "required": [ "clean", "truncated", "files_truncated", "changes_truncated", "listed_file_count", "files", "changes" ], "type": "object" }, "ApplicationWorkspaceDiffResponse": { "properties": { "diff": { "type": "string" }, "path": { "type": "string" }, "truncated": { "type": "boolean" } }, "required": [ "path", "diff", "truncated" ], "type": "object" }, "ApplicationWorkspaceDirectoryEntryResponse": { "properties": { "kind": { "type": "string" }, "name": { "type": "string" }, "path": { "type": "string" }, "size_bytes": { "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "name", "path", "kind", "size_bytes" ], "type": "object" }, "ApplicationWorkspaceDirectoryResponse": { "properties": { "entries": { "items": { "$ref": "#/components/schemas/ApplicationWorkspaceDirectoryEntryResponse" }, "type": "array" }, "next_cursor": { "minimum": 0, "type": [ "integer", "null" ] }, "path": { "type": "string" }, "truncated": { "type": "boolean" } }, "required": [ "path", "entries", "truncated" ], "type": "object" }, "ApplicationWorkspaceFileContentResponse": { "properties": { "binary": { "type": "boolean" }, "content": { "type": [ "string", "null" ] }, "content_b64": { "description": "Base64-encoded raster image bytes when this file has a verified,\nbrowser-safe image signature and is within the configured preview cap.", "type": [ "string", "null" ] }, "media_type": { "type": [ "string", "null" ] }, "path": { "type": "string" }, "size_bytes": { "format": "int64", "minimum": 0, "type": "integer" }, "truncated": { "type": "boolean" } }, "required": [ "path", "binary", "size_bytes", "truncated" ], "type": "object" }, "ApplicationWorkspaceFileResponse": { "properties": { "path": { "type": "string" }, "staged": { "type": "boolean" }, "status": { "type": [ "string", "null" ] }, "unstaged": { "type": "boolean" } }, "required": [ "path", "staged", "unstaged" ], "type": "object" }, "ApplicationWorkspaceFileWrite": { "additionalProperties": false, "properties": { "contents_b64": { "type": "string" }, "mode": { "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "path": { "description": "Project-relative path. Absolute paths and traversal are rejected.", "type": "string" } }, "required": [ "path", "contents_b64" ], "type": "object" }, "ApplicationWorkspaceResponse": { "properties": { "cpu_limit": { "format": "double", "type": "number" }, "cpu_usage_usec": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "data_network_service_count": { "minimum": 0, "type": "integer" }, "desired_state": { "type": "string" }, "disk_limit_enforced": { "description": "Docker bind-mounted workspaces report usage but cannot enforce a\nper-directory quota. Firecracker workspaces enforce this value.", "type": "boolean" }, "disk_limit_mb": { "format": "int64", "type": "integer" }, "disk_used_bytes": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "idle_timeout_secs": { "format": "int64", "type": "integer" }, "image": { "type": [ "string", "null" ] }, "last_error": { "type": [ "string", "null" ] }, "memory_limit_mb": { "format": "int64", "type": "integer" }, "memory_used_bytes": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "open_preview_ports": { "items": { "format": "int32", "minimum": 0, "type": "integer" }, "type": "array" }, "persistent_volume_healthy": { "type": "boolean" }, "pids_limit": { "format": "int64", "type": "integer" }, "pids_used": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "runtime": { "type": "string" }, "runtime_compatible": { "type": [ "boolean", "null" ] }, "runtime_update_available": { "type": "boolean" }, "runtime_update_error": { "type": [ "string", "null" ] }, "runtime_update_image": { "type": [ "string", "null" ] }, "sandbox_public_id": { "type": [ "string", "null" ] }, "snapshot_id": { "type": [ "string", "null" ] }, "state": { "type": "string" } }, "required": [ "state", "desired_state", "runtime", "runtime_update_available", "cpu_limit", "memory_limit_mb", "pids_limit", "disk_limit_mb", "disk_limit_enforced", "idle_timeout_secs", "open_preview_ports", "persistent_volume_healthy", "data_network_service_count" ], "type": "object" }, "ApplyDomainDeliveryBindingRequest": { "properties": { "adopt_records": { "items": { "$ref": "#/components/schemas/AdoptDeliveryRecord" }, "type": "array" }, "preview_id": { "type": "string" } }, "required": [ "preview_id" ], "type": "object" }, "ApplyHostnameModeRequest": { "description": "Request to apply a hostname mode (recompute + optional DNS sync).", "properties": { "adopt_records": { "description": "Conflicting records, from the preview's `conflicts`, that the user\nconfirmed the sync may adopt — one entry per record, each only where\nthe conflict is `adoptable`. Requires `sync_dns`.", "items": { "$ref": "#/components/schemas/AdoptHostnameRecord" }, "type": "array" }, "mode": { "description": "Target mode to apply: `\"standard\"` or `\"flat\"`.", "type": "string" }, "skip_records": { "description": "Conflicting hostnames, from the preview's `conflicts`, that the user\nchose to leave untouched: the sync writes everything else. Requires\n`sync_dns`.", "items": { "$ref": "#/components/schemas/SkipHostnameRecord" }, "type": "array" }, "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" }, "ArtifactKind": { "description": "The formats local checks read. Adding one needs no migration or new check kind.", "enum": [ "x509_certificate", "ssh_certificate", "openpgp_key", "jwt" ], "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" }, "AttrOp": { "enum": [ "eq", "neq", "exists", "prefix", "gt", "lt" ], "type": "string" }, "AttrPredicate": { "description": "Predicate on one attribute (canonical or dynamic).", "properties": { "key": { "description": "Attribute key: a canonical key (`status_code`, `http_route`, …) or\nany extracted key (`worker`, `http.status`).", "type": "string" }, "op": { "$ref": "#/components/schemas/AttrOp" }, "value": { "description": "Omitted for `exists`.", "type": [ "string", "null" ] } }, "required": [ "key" ], "type": "object" }, "AttributeKeysResponse": { "properties": { "keys": { "items": { "$ref": "#/components/schemas/FacetValue" }, "type": "array" } }, "required": [ "keys" ], "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": [ { "$ref": "#/components/schemas/AuditLogIpInfo", "description": "IP address details" }, { "type": "null" } ] }, "operation_type": { "description": "The type of action that was performed", "example": "USER_LOGIN", "type": "string" }, "user": { "oneOf": [ { "$ref": "#/components/schemas/AuditLogUserInfo", "description": "User details who performed the action" }, { "type": "null" } ] }, "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_enrollment_required": { "type": "boolean" }, "mfa_required": { "type": "boolean" }, "mfa_setup": { "oneOf": [ { "$ref": "#/components/schemas/MfaSetupResponse" }, { "type": "null" } ] }, "password_change_required": { "type": "boolean" }, "success": { "type": "boolean" }, "user_id": { "format": "int32", "type": [ "integer", "null" ] } }, "required": [ "success", "message", "mfa_required", "mfa_enrollment_required", "password_change_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" }, "AuthorizeWorkspacePreviewRequest": { "properties": { "path": { "type": [ "string", "null" ] }, "port": { "format": "int32", "minimum": 0, "type": "integer" }, "sandbox_public_id": { "type": "string" } }, "required": [ "sandbox_public_id", "port" ], "type": "object" }, "AuthorizedEmailDomainProjectResponse": { "description": "A project authorized to send email through a sender domain.", "properties": { "id": { "format": "int32", "type": "integer" }, "name": { "type": "string" }, "slug": { "type": "string" } }, "required": [ "id", "name", "slug" ], "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": [ { "$ref": "#/components/schemas/AutofixRunConfig", "description": "Per-run options the run was started with; used to prefill the\nretry / start-over dialog." }, { "type": "null" } ] }, "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" }, "AvailableAiProviderDto": { "properties": { "auth_source": { "description": "`configured_key` for an encrypted gateway key.", "type": "string" }, "default_model_id": { "type": [ "string", "null" ] }, "default_permission_mode_id": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "model_discovery_error": { "type": [ "string", "null" ] }, "model_discovery_status": { "description": "`ready` when the model list was loaded, `unavailable` when the provider\ncan still run with its own default but live discovery failed.", "type": "string" }, "models": { "items": { "$ref": "#/components/schemas/AiModelOptionDto" }, "type": "array" }, "name": { "type": "string" }, "permission_modes": { "items": { "$ref": "#/components/schemas/AiSelectOptionDto" }, "type": "array" } }, "required": [ "id", "name", "auth_source", "models", "model_discovery_status", "permission_modes" ], "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": [ { "$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)." }, { "type": "null" } ] }, "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" }, "BatchObject": { "allOf": [ { "type": "object" }, { "properties": { "completion_window": { "type": "string" }, "created_at": { "format": "int64", "type": "integer" }, "endpoint": { "type": "string" }, "error_file_id": { "description": "Results of the failed requests.", "type": [ "string", "null" ] }, "id": { "type": "string" }, "input_file_id": { "type": "string" }, "model": { "type": [ "string", "null" ] }, "object": { "description": "Always `batch`", "type": "string" }, "output_file_id": { "description": "Results of the successful requests; download with\n`GET /ai/v1/files/{file_id}/content`.", "type": [ "string", "null" ] }, "request_counts": { "oneOf": [ { "$ref": "#/components/schemas/BatchRequestCounts" }, { "type": "null" } ] }, "status": { "description": "`validating`, `in_progress`, `finalizing`, `completed`, `failed`,\n`expired`, `cancelling` or `cancelled`", "type": "string" }, "usage": { "oneOf": [ { "$ref": "#/components/schemas/BatchUsage" }, { "type": "null" } ] } }, "required": [ "id", "object", "status" ], "type": "object" } ], "description": "A batch object as returned by the provider." }, "BatchRequestCounts": { "description": "Progress counters of a batch.", "properties": { "completed": { "format": "int64", "type": "integer" }, "failed": { "format": "int64", "type": "integer" }, "total": { "format": "int64", "type": "integer" } }, "type": "object" }, "BatchUsage": { "description": "Token usage of a finished batch, summed over its requests.", "properties": { "input_tokens": { "format": "int64", "type": "integer" }, "output_tokens": { "format": "int64", "type": "integer" }, "total_tokens": { "format": "int64", "type": "integer" } }, "type": "object" }, "BindApplicationGitConnectionRequest": { "properties": { "connectionId": { "format": "int32", "type": "integer" }, "projectId": { "format": "int32", "type": "integer" }, "remoteName": { "type": "string" }, "repositoryId": { "format": "int32", "type": "integer" } }, "required": [ "projectId", "connectionId", "repositoryId", "remoteName" ], "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": "rustfs/rustfs:1.0.0-rc.5", "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": "1.0.0-rc.5", "type": [ "string", "null" ] } }, "required": [ "enabled", "healthy" ], "type": "object" }, "BranchInfo": { "properties": { "commit_sha": { "type": "string" }, "is_default": { "description": "Whether this is the repository's default branch, as reported by the\ngit provider (e.g. `main` or `master`). Clients should use this\ninstead of guessing from the branch name.", "type": "boolean" }, "name": { "type": "string" }, "protected": { "type": "boolean" } }, "required": [ "name", "commit_sha", "protected", "is_default" ], "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\". Applied only\nby Docker's legacy builder: BuildKit, the default since Docker 18.09,\nignores the CPU and memory options of the image build API, so on\nBuildKit hosts this has no effect. Read once at startup; a change\ntakes effect after `temps serve` restarts.", "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\". Same scope as `cpu_limit_cores`: applied only\nby the legacy builder, ignored by BuildKit, read once at startup.\nValues above 2047 MB are reduced to 2047 MB, the most the build API\naccepts through the client, with a warning in the server log.", "example": 2048, "format": "int32", "minimum": 0, "type": "integer" } }, "type": "object" }, "BulkActivationEstimateResponse": { "description": "The quote.", "properties": { "active_batch_id": { "description": "A job already running. Submitting would be refused with `409`, so the\nclient can offer \"watch the running job\" instead of a button that fails.", "type": [ "string", "null" ] }, "configured": { "description": "Whether a bulk activation could run at all right now.\n\n`false` is the normal state on an unlinked instance and must render as\nonboarding, not as an error.", "type": "boolean" }, "eligible_projects": { "minimum": 0, "type": "integer" }, "estimated_bytes": { "format": "int64", "minimum": 0, "type": "integer" }, "estimated_spans": { "description": "Totals over the **eligible** projects only — what confirming this quote\nwould actually send.", "format": "int64", "minimum": 0, "type": "integer" }, "plan_expires_at": { "format": "date-time", "type": [ "string", "null" ] }, "plan_hash": { "description": "Stable identity of the project set and windows, recorded on the job.", "type": [ "string", "null" ] }, "plan_token": { "description": "The handle to send back to `POST /bulk-jobs`.\n\n`None` when nothing is eligible: there is no bill to confirm, and\nhanding back a token that would be refused on submit would be a dead\nend with no explanation attached.", "type": [ "string", "null" ] }, "projects": { "description": "Every project considered, eligible or not, ascending by id.", "items": { "$ref": "#/components/schemas/BulkActivationProjectEstimateResponse" }, "type": "array" }, "reason": { "type": [ "string", "null" ] }, "setup_path": { "type": [ "string", "null" ] }, "skipped_projects": { "minimum": 0, "type": "integer" }, "total_projects": { "minimum": 0, "type": "integer" }, "window_from": { "format": "date-time", "type": "string" }, "window_to": { "format": "date-time", "type": "string" } }, "required": [ "configured", "window_from", "window_to", "projects", "total_projects", "eligible_projects", "skipped_projects", "estimated_spans", "estimated_bytes" ], "type": "object" }, "BulkActivationEtaState": { "description": "How much of the ETA this instance can honestly claim to know.", "enum": [ "estimating", "known", "finished" ], "type": "string" }, "BulkActivationJobProjectResponse": { "description": "One project's row inside a job.", "properties": { "bytes_shipped": { "format": "int64", "type": "integer" }, "completed_at": { "format": "date-time", "type": [ "string", "null" ] }, "estimated_bytes": { "format": "int64", "type": "integer" }, "estimated_spans": { "format": "int64", "type": "integer" }, "last_error": { "description": "Why this project stopped, when `status` is `failed`. The switch is never\nrolled back, so this project is Cloud-primary with a recorded hole in\nits history — which is retryable, and must be visible to be retried.", "type": [ "string", "null" ] }, "percent_complete": { "description": "`spans_shipped / estimated_spans`, clamped to 0–100. `None` when the\nestimate is zero or unknown — an empty window is not \"0% done\".", "format": "double", "type": [ "number", "null" ] }, "project_id": { "format": "int32", "type": "integer" }, "setup_path": { "type": [ "string", "null" ] }, "skip_detail": { "type": [ "string", "null" ] }, "skip_reason": { "type": [ "string", "null" ] }, "spans_shipped": { "format": "int64", "type": "integer" }, "started_at": { "format": "date-time", "type": [ "string", "null" ] }, "status": { "$ref": "#/components/schemas/BulkJobProjectStatus" }, "window_from": { "format": "date-time", "type": "string" }, "window_to": { "format": "date-time", "type": "string" } }, "required": [ "project_id", "status", "window_from", "window_to", "estimated_spans", "estimated_bytes", "spans_shipped", "bytes_shipped" ], "type": "object" }, "BulkActivationJobResponse": { "description": "A job, its projects, its progress and its ETA.", "properties": { "abort_detail": { "description": "The same reason as a sentence naming the fix and the page that applies\nit.", "type": [ "string", "null" ] }, "abort_reason": { "description": "Machine-readable instance-wide abort reason, e.g. `not_linked`.", "type": [ "string", "null" ] }, "batch_id": { "type": "string" }, "bytes_shipped": { "format": "int64", "type": "integer" }, "cancel_requested": { "description": "Set as soon as a cancel is requested, before the worker honours it at\nthe next chunk boundary — so the UI can stop offering Cancel twice.", "type": "boolean" }, "cancel_requested_at": { "format": "date-time", "type": [ "string", "null" ] }, "completed_at": { "format": "date-time", "type": [ "string", "null" ] }, "created_at": { "format": "date-time", "type": "string" }, "current_project_id": { "description": "The project being switched or backfilled right now.", "format": "int32", "type": [ "integer", "null" ] }, "estimated_bytes": { "format": "int64", "type": "integer" }, "estimated_spans": { "format": "int64", "type": "integer" }, "eta_seconds": { "description": "Seconds remaining, or `null` when `eta_state` is not `known`.", "format": "int64", "type": [ "integer", "null" ] }, "eta_state": { "$ref": "#/components/schemas/BulkActivationEtaState" }, "observed_spans_per_sec": { "description": "The average this job has actually achieved since it started. Sent so the\nclient can render a coarse rate instead of implying a precision the\naverage does not have.", "format": "double", "type": [ "number", "null" ] }, "percent_complete": { "format": "double", "type": [ "number", "null" ] }, "plan_hash": { "type": [ "string", "null" ] }, "projects": { "items": { "$ref": "#/components/schemas/BulkActivationJobProjectResponse" }, "type": "array" }, "projects_done": { "minimum": 0, "type": "integer" }, "projects_failed": { "minimum": 0, "type": "integer" }, "projects_pending": { "minimum": 0, "type": "integer" }, "projects_skipped": { "minimum": 0, "type": "integer" }, "projects_total": { "minimum": 0, "type": "integer" }, "requested_by_user_id": { "format": "int32", "type": [ "integer", "null" ] }, "spans_shipped": { "format": "int64", "type": "integer" }, "started_at": { "format": "date-time", "type": [ "string", "null" ] }, "status": { "$ref": "#/components/schemas/BulkJobStatus" }, "trigger": { "$ref": "#/components/schemas/BulkJobTrigger" } }, "required": [ "batch_id", "trigger", "status", "estimated_spans", "estimated_bytes", "spans_shipped", "bytes_shipped", "eta_state", "projects_total", "projects_pending", "projects_done", "projects_failed", "projects_skipped", "cancel_requested", "created_at", "projects" ], "type": "object" }, "BulkActivationProjectEstimateResponse": { "description": "One project's line on the quote.", "properties": { "average_span_bytes": { "format": "double", "type": "number" }, "eligible": { "description": "Whether this project is part of the plan the token covers.", "type": "boolean" }, "estimated_bytes": { "description": "`average_span_bytes * estimated_spans`, rounded up. Temps Cloud's own\nacknowledgement is authoritative; this is what this instance can know\nbefore sending.", "format": "int64", "minimum": 0, "type": "integer" }, "estimated_spans": { "description": "Exact count of local spans in the window. Zero for a skipped project —\nnothing was counted, because nothing would be sent.", "format": "int64", "minimum": 0, "type": "integer" }, "fidelity": { "$ref": "#/components/schemas/CloudTelemetryFidelity" }, "project_id": { "format": "int32", "type": "integer" }, "sampled_spans": { "description": "How many spans were actually projected to derive the average.", "format": "int64", "minimum": 0, "type": "integer" }, "setup_path": { "description": "Where the operator goes to unblock it, when anywhere.", "type": [ "string", "null" ] }, "skip_detail": { "description": "The same reason as a sentence, so no client has to map an enum to prose.", "type": [ "string", "null" ] }, "skip_reason": { "description": "Machine-readable reason it is not, e.g. `fidelity_not_queryable`.", "type": [ "string", "null" ] }, "window_from": { "format": "date-time", "type": "string" }, "window_to": { "format": "date-time", "type": "string" } }, "required": [ "project_id", "eligible", "fidelity", "window_from", "window_to", "estimated_spans", "estimated_bytes", "sampled_spans", "average_span_bytes" ], "type": "object" }, "BulkAlarmActionRequest": { "description": "Lifecycle transition for `POST .../alarms/bulk`.", "enum": [ "acknowledge", "resolve" ], "type": "string" }, "BulkAlarmFilter": { "description": "Filters selecting \"every alarm matching\" for a bulk update. Same\nsemantics as the list endpoint's query parameters.", "properties": { "alarm_type": { "description": "Filter by alarm type (e.g. `container_crash`).", "type": [ "string", "null" ] }, "deployment_id": { "description": "Filter by deployment ID.", "format": "int32", "type": [ "integer", "null" ] }, "environment_id": { "description": "Filter by environment ID.", "format": "int32", "type": [ "integer", "null" ] }, "severity": { "description": "Filter by severity: `info`, `warning`, or `critical`.", "type": [ "string", "null" ] }, "status": { "description": "Filter by status: `firing` or `acknowledged`.", "type": [ "string", "null" ] } }, "type": "object" }, "BulkAlarmRequest": { "description": "Request body for `POST .../alarms/bulk`. Provide exactly one of\n`alarm_ids` or `filter`.", "properties": { "action": { "$ref": "#/components/schemas/BulkAlarmActionRequest" }, "alarm_ids": { "description": "Explicit alarms to update (at most 1000).", "items": { "format": "int32", "type": "integer" }, "type": [ "array", "null" ] }, "filter": { "oneOf": [ { "$ref": "#/components/schemas/BulkAlarmFilter", "description": "Update every alarm matching these filters, up to 1000 per request.\nUse `{}` to match all active alarms in scope." }, { "type": "null" } ] } }, "required": [ "action" ], "type": "object" }, "BulkAlarmResponse": { "description": "Result of a bulk alarm update.", "properties": { "action": { "$ref": "#/components/schemas/BulkAlarmActionRequest" }, "remaining": { "description": "Matching alarms left for a follow-up request because this one hit the\nper-request limit. Always 0 when `alarm_ids` was used.", "format": "int64", "minimum": 0, "type": "integer" }, "skipped": { "description": "Requested alarms already in (or past) the target state.", "format": "int64", "minimum": 0, "type": "integer" }, "updated": { "description": "Number of alarms that changed state.", "format": "int64", "minimum": 0, "type": "integer" }, "updated_ids": { "description": "IDs of the alarms that changed state.", "items": { "format": "int32", "type": "integer" }, "type": "array" } }, "required": [ "action", "updated", "updated_ids", "skipped", "remaining" ], "type": "object" }, "BulkJobProjectStatus": { "description": "Where one project has got to inside a bulk job.\n\n`switching` and `backfilling` are separate on purpose: the switch is cheap,\natomic and egresses nothing, while the backfill can run for hours and costs\nmoney. An operator watching a stuck job needs to know which of the two it is\nstuck in, and a project that failed after switching is *not* rolled back\n(ADR-042 §7) — so the two must be distinguishable after the fact too.", "enum": [ "pending", "switching", "backfilling", "done", "failed", "skipped" ], "type": "string" }, "BulkJobStatus": { "description": "Lifecycle of a bulk job.\n\nThe three terminal-with-a-problem states are deliberately distinct.\n`completed_with_failures` means the job ran to the end and some projects\ndid not; `aborted` means an instance-wide condition stopped it and the\nuntouched projects are still `pending`, ready to resume; `cancelled` means\nan operator asked it to stop. Collapsing any two of those would leave the\nConsole unable to say what to do next.", "enum": [ "pending", "running", "completed", "completed_with_failures", "aborted", "cancelled" ], "type": "string" }, "BulkJobTrigger": { "description": "Which entry point created the job (ADR-042 §1).\n\nThe engine does not branch on this. It exists so an operator disputing an\ninvoice, or reading an audit trail, can tell \"this instance spent money\nbecause someone clicked a button\" apart from \"…because a purchase completed\nand the payment was the authorization\".", "enum": [ "purchase", "operator" ], "type": "string" }, "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" }, "Candidate": { "description": "Detection output deliberately contains neither the secret nor matching substrings.", "properties": { "description": { "type": "string" }, "evidence": { "$ref": "#/components/schemas/DetectionEvidence" }, "id": { "type": "string" } }, "required": [ "id", "description", "evidence" ], "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": [ { "$ref": "#/components/schemas/OnDemandCertAttemptResponse", "description": "The most recent on-demand issuance attempt for this hostname, if any." }, { "type": "null" } ] }, "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": [ { "$ref": "#/components/schemas/ChallengeError", "description": "Error details if validation failed" }, { "type": "null" } ] }, "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" }, "ChatAttachmentReference": { "properties": { "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ], "type": "object" }, "ChatAttachmentResponse": { "properties": { "id": { "type": "string" }, "is_image": { "type": "boolean" }, "mime_type": { "type": "string" }, "name": { "type": "string" }, "sandbox_path": { "type": "string" }, "size_bytes": { "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "id", "name", "mime_type", "size_bytes", "sandbox_path", "is_image" ], "type": "object" }, "ChatAttachmentUpload": { "properties": { "file": { "format": "binary", "type": "string" } }, "required": [ "file" ], "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": [ { "$ref": "#/components/schemas/StopSequence" }, { "type": "null" } ] }, "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": [ { "$ref": "#/components/schemas/UsageInfo" }, { "type": "null" } ] } }, "required": [ "id", "object", "created", "model", "choices" ], "type": "object" }, "ChatFailureResponse": { "properties": { "code": { "type": "string" }, "detail": { "type": "string" }, "retryable": { "type": "boolean" }, "title": { "type": "string" } }, "required": [ "code", "title", "detail", "retryable" ], "type": "object" }, "ChatMessage": { "properties": { "content": { "oneOf": [ { "$ref": "#/components/schemas/MessageContent" }, { "type": "null" } ] }, "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.", "properties": { "ai_configured": { "description": "An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project.", "type": "boolean" } }, "required": [ "ai_configured" ], "type": "object" }, "CheckKind": { "description": "What a stored check does: HTTP checks call an issuer; local checks read\nexpiring items (certificates, SSH certificates, OpenPGP keys, kubeconfigs,\nJWTs) on this host and never transmit the value.", "enum": [ "http", "local" ], "type": "string" }, "CheckStatus": { "enum": [ "healthy", "warning", "error", "unknown" ], "type": "string" }, "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" }, "CloudAiCapability": { "properties": { "configured": { "type": "boolean" }, "model": { "type": [ "string", "null" ] }, "reason": { "type": [ "string", "null" ] }, "setup_path": { "type": "string" } }, "required": [ "configured", "setup_path" ], "type": "object" }, "CloudAnalyticsWriteMode": { "description": "Per-project destination for analytics and metrics writes (ADR-043 §1).", "enum": [ "local", "cloud" ], "type": "string" }, "CloudBackfillStatusResponse": { "properties": { "backfill_available": { "description": "Whether a backfill would be accepted right now. False means the project\nis still at `metered` fidelity.", "type": "boolean" }, "command": { "description": "The exact command an operator should run. Always present, in every\nstate, so the capability is discoverable from the Console even though\nthe Console deliberately cannot trigger it.", "type": "string" }, "completed_at": { "format": "date-time", "type": [ "string", "null" ] }, "fidelity": { "$ref": "#/components/schemas/CloudTelemetryFidelity", "description": "Current per-project egress fidelity. A `metered` project cannot be\nbackfilled at all — the CLI refuses — so the client must be able to\nrender \"not set up\" rather than \"not started\"." }, "last_error": { "description": "Reason the last run stopped, when `status` is `failed`. Verbatim, but\nlength-bounded: it originates as raw driver/server text and is readable\nby every project member with `OtelRead`, not only whoever ran the\ncommand.", "type": [ "string", "null" ] }, "percent_complete": { "description": "`spans_processed / spans_total`, clamped to 0–100. `None` when the total\nis unknown or zero — an empty window is not \"0% done\".", "format": "double", "type": [ "number", "null" ] }, "project_id": { "format": "int32", "type": "integer" }, "setup_path": { "description": "Where to go to raise fidelity, when `backfill_available` is false.", "type": [ "string", "null" ] }, "spans_processed": { "format": "int64", "type": "integer" }, "spans_total": { "format": "int64", "type": "integer" }, "started_at": { "format": "date-time", "type": [ "string", "null" ] }, "status": { "$ref": "#/components/schemas/CloudTelemetryBackfillStatus", "description": "`not_started` when no backfill has ever run for this project." }, "updated_at": { "description": "Bumped on every progress write. A `running` status whose `updated_at` is\nfar in the past is a stalled run, and the client should say so instead\nof showing a spinner forever.", "format": "date-time", "type": [ "string", "null" ] }, "window_from": { "format": "date-time", "type": [ "string", "null" ] }, "window_to": { "format": "date-time", "type": [ "string", "null" ] } }, "required": [ "project_id", "status", "fidelity", "backfill_available", "spans_processed", "spans_total", "command" ], "type": "object" }, "CloudCapability": { "properties": { "configured": { "type": "boolean" }, "reason": { "type": [ "string", "null" ] }, "setup_path": { "type": "string" } }, "required": [ "configured", "setup_path" ], "type": "object" }, "CloudDeliveryGapResponse": { "description": "A stretch of span time whose spans reached this instance but were never\ndelivered to Temps Cloud (their retries were exhausted).\n\nDistinct from [`TelemetryGapWindowResponse`], which records spans refused\nat the door because the queue was full: these were accepted and queued, and\nthe loss happened later, on the way out.", "properties": { "first_span_at": { "description": "When the earliest undelivered span in this stretch reached the instance.", "format": "date-time", "type": "string" }, "gave_up_at": { "description": "When delivery of the latest span in this stretch gave up — the same\nfailure `last_error` describes.", "format": "date-time", "type": [ "string", "null" ] }, "last_error": { "description": "The instance's own bounded failure reason — never span content.", "type": [ "string", "null" ] }, "last_span_at": { "description": "When the latest one did. Traces between the two are incomplete.", "format": "date-time", "type": "string" }, "undelivered_spans": { "format": "int64", "type": "integer" } }, "required": [ "first_span_at", "last_span_at", "undelivered_spans" ], "type": "object" }, "CloudFeatureSwitchesRequest": { "properties": { "backups_enabled": { "type": [ "boolean", "null" ] }, "console_access_enabled": { "description": "Omitted switches retain their current value under the settings row lock.", "type": [ "boolean", "null" ] }, "notifications_enabled": { "type": [ "boolean", "null" ] }, "telemetry_enabled": { "type": [ "boolean", "null" ] } }, "type": "object" }, "CloudProvider": { "description": "Cloud provider detected from node metadata", "enum": [ "aws", "gcp", "azure", "hetzner", "digitalocean", "other" ], "type": "string" }, "CloudSettings": { "description": "Non-secret managed control-plane settings stored with application settings.\n\n`PartialEq` but deliberately **not** `Eq`: `telemetry_bulk_anomaly_factor` is\na float, and the total-equality contract `Eq` promises is one `f32` cannot\nkeep. Nothing compares two `CloudSettings` for equality outside this module's\nown tests, so the weaker bound costs nothing.", "properties": { "backend_url": { "default": "https://app.temps.sh", "description": "HTTPS origin used for enrollment and telemetry mirroring.", "type": "string" }, "backups_enabled": { "default": false, "description": "Explicit consent to export completed backup objects.", "type": "boolean" }, "console_access_enabled": { "default": false, "description": "Explicit operator consent to let Temps Cloud open this instance's\nconsole over the outbound relay, using managed OIDC authentication.\nDefault off for every enrollment path. Linking, including unattended\nbootstrap, never enables console access; enable it explicitly in\nSettings > Temps Cloud or with `temps cloud console-access enable`.", "type": "boolean" }, "notifications_enabled": { "default": false, "description": "Explicit consent to send notifications through managed providers.", "type": "boolean" }, "telemetry_bulk_anomaly_factor": { "default": null, "description": "ADR-042 §6.3: how far a project's shipped bytes may exceed its pre-send\nestimate before the bulk activation stops that project.\n\n`None` — the default — resolves to\n[`DEFAULT_CLOUD_TELEMETRY_BULK_ANOMALY_FACTOR`]. The guard exists because\nan estimate that is wrong by an order of magnitude means a bug, and *a\nbug that costs money should stop* rather than run away with a customer's\negress spend on a path that has no human confirm behind it.\n\nAn operator setting on the singleton `settings` row rather than an\nenvironment variable, per CLAUDE.md: the right multiple depends on how\nheterogeneous that instance's spans actually are, which only the operator\nrunning it can know, and they must be able to widen it — or narrow it —\nwithout restarting the binary mid-activation.\n\nBelow `1.0` every project would pause on its first chunk, and above\n[`MAX_CLOUD_TELEMETRY_BULK_ANOMALY_FACTOR`] the guard stops being a\ntuning knob and becomes an off switch. The settings write path rejects\nvalues outside that range, and the effective value is clamped on read\nbesides; see [`CloudSettings::effective_bulk_anomaly_factor`].\n\nThe schema bounds below are documentation for a client; they are not\nwhat enforces this. The server validates the range on write.", "example": 5, "format": "float", "maximum": 50, "minimum": 1, "type": [ "number", "null" ] }, "telemetry_bulk_rate_limit_spans_per_sec": { "default": null, "description": "ADR-042 §3: optional throttle, in spans per second, on a **bulk Cloud\ntelemetry activation** backfill.\n\n`None` — the default — is unthrottled, which is what \"activate now\"\nmeans and is right for an instance that is idle or being cut over\ndeliberately. An operator running an activation against a live instance\ncan set a ceiling so the backfill stops competing with their own read IO\nand with the Cloud ingest allowance.\n\nAn operator setting on the singleton `settings` row rather than an\nenvironment variable, per CLAUDE.md, so it can be changed **while a job\nis running** — which is exactly when an operator discovers they need it,\nand exactly when restarting the binary would mean stopping an activation\nthey have already paid for. The worker re-reads it each time it picks up\na project, so a change takes effect at the next project boundary rather\nthan at the next restart.\n\nOnly the bulk worker reads this. The live Cloud-primary write path is a\nprimary path and is never throttled; the offline\n`temps backfill cloud-telemetry` tool keeps its own\n`--rate-limit-spans-per-sec` flag, because it runs in a different\nprocess with the server stopped.", "example": 5000, "format": "int32", "minimum": 1, "type": [ "integer", "null" ] }, "telemetry_enabled": { "default": false, "description": "Explicit consent to mirror locally stored telemetry.", "type": "boolean" }, "telemetry_outbox_max_bytes": { "default": 536870912, "description": "ADR-041 §3d: hard ceiling, in bytes, on the durable span outbox that\nbacks Cloud-primary telemetry writes.\n\nAn operator setting on the singleton `settings` row rather than an\nenvironment variable, per CLAUDE.md, so it can be raised at runtime by\nthe operator watching a queue fill up — which is exactly when they need\nto change it and exactly when restarting the binary is the worst\navailable option.\n\nExpressed in **bytes and not rows**: the reference deployment is\n3 vCPU / 4 GB, and a row count says nothing about disk on a table whose\nrows are serialized spans of wildly varying size. When the queue reaches\nthis size the instance stops accepting new spans for Cloud-primary\nprojects and records a gap window with a start, an end and a count —\nsee [`DEFAULT_CLOUD_TELEMETRY_OUTBOX_MAX_BYTES`] for how the default is\nsized and what it buys.", "example": 536870912, "format": "int64", "minimum": 1048576, "type": "integer" } }, "type": "object" }, "CloudStatus": { "properties": { "account_email": { "type": [ "string", "null" ] }, "backend_url": { "type": "string" }, "backups_enabled": { "type": "boolean" }, "console_access_enabled": { "description": "ADR-045 §5: whether this instance currently permits Temps Cloud to\nopen its console over the console-proxy tunnel.", "type": "boolean" }, "health": { "type": "string" }, "health_message": { "type": "string" }, "instance_id": { "type": [ "string", "null" ] }, "managed_backup_setup": { "$ref": "#/components/schemas/ManagedBackupSetup" }, "notifications_enabled": { "type": "boolean" }, "spooled_spans": { "minimum": 0, "type": "integer" }, "status": { "type": "string" }, "status_message": { "type": "string" }, "telemetry_enabled": { "type": "boolean" } }, "required": [ "status", "status_message", "health", "health_message", "spooled_spans", "backend_url", "telemetry_enabled", "backups_enabled", "notifications_enabled", "console_access_enabled", "managed_backup_setup" ], "type": "object" }, "CloudTelemetryBackfillStatus": { "description": "Lifecycle of the most recent backfill run for a project.", "enum": [ "not_started", "running", "completed", "failed" ], "type": "string" }, "CloudTelemetryFidelity": { "description": "Per-project fidelity tier for the optional Temps Cloud telemetry mirror.", "enum": [ "metered", "queryable" ], "type": "string" }, "CloudTelemetryWriteMode": { "description": "Per-project destination for span writes.", "enum": [ "local", "cloud" ], "type": "string" }, "CloudTelemetryWriteStatusResponse": { "description": "Instance-wide aggregate for the Cloud settings page.", "properties": { "can_decommission_local_span_store": { "description": "Whether the console should offer decommission guidance. True only when\n`local_span_store_required` is false — the ADR is explicit that the\nadvice must not appear before then.", "type": "boolean" }, "cloud_primary_projects": { "format": "int64", "minimum": 0, "type": "integer" }, "configured": { "description": "Whether Cloud-primary writes can be used at all on this instance.", "type": "boolean" }, "dead_lettered_rows": { "description": "Rows that exhausted their retries. Never swept automatically; an\noperator has to see them.", "format": "int64", "type": "integer" }, "gap_windows": { "items": { "$ref": "#/components/schemas/TelemetryGapWindowResponse" }, "type": "array" }, "local_history_until": { "format": "date-time", "type": [ "string", "null" ] }, "local_mode_projects": { "format": "int64", "minimum": 0, "type": "integer" }, "local_span_store_reason": { "type": [ "string", "null" ] }, "local_span_store_required": { "description": "The derived decommission signal. `true` means the operator gets **zero**\nresource win from removing their local span store, whatever the write\nmodes say.", "type": "boolean" }, "oldest_unshipped_age_secs": { "description": "Age of the oldest unshipped span, in seconds. `None` when the queue is\nempty — different from zero, and it must not render as zero.", "format": "int64", "type": [ "integer", "null" ] }, "queue_bytes": { "format": "int64", "type": "integer" }, "queue_depth": { "description": "Spans queued for Cloud across all projects.", "format": "int64", "type": "integer" }, "queue_max_bytes": { "description": "The operator-set ceiling, so the depth above is readable against\nsomething rather than being a number with no scale.", "format": "int64", "minimum": 0, "type": "integer" }, "reason": { "type": [ "string", "null" ] }, "setup_path": { "type": [ "string", "null" ] }, "write_suspension": { "description": "Set while Cloud-primary writes are falling back to local storage.", "type": [ "string", "null" ] } }, "required": [ "configured", "cloud_primary_projects", "local_mode_projects", "local_span_store_required", "queue_depth", "queue_bytes", "queue_max_bytes", "dead_lettered_rows", "gap_windows", "can_decommission_local_span_store" ], "type": "object" }, "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" }, "CloudflareProjectCapability": { "description": "Cloudflare availability and the default used by future project creation.", "properties": { "bunny_configured": { "type": "boolean" }, "bunny_default_enabled": { "type": "boolean" }, "bunny_reason": { "type": [ "string", "null" ] }, "configured": { "type": "boolean" }, "default_enabled": { "type": "boolean" }, "reason": { "type": [ "string", "null" ] }, "setup_path": { "type": [ "string", "null" ] } }, "required": [ "configured", "default_enabled", "bunny_configured", "bunny_default_enabled" ], "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" }, "ClusterDnsStatusResponse": { "description": "Response from `GET /api/cluster/dns/status`.", "properties": { "cluster_dns_enabled": { "description": "Whether cluster DNS is currently enabled cluster-wide\n(`AppSettings.cluster_dns.enabled`). When `false`, every node's\nper-node values below are expected to show `dns_resolver_running:\nSome(false)` (or `None` if a node has never reported).", "type": "boolean" }, "nodes": { "items": { "$ref": "#/components/schemas/NodeDnsStatusEntry" }, "type": "array" }, "total_record_count": { "description": "Total `*.temps.local` records currently registered across the whole\ncluster (`service_endpoints` row count), independent of any single\nnode's resolver health.", "format": "int64", "type": "integer" } }, "required": [ "cluster_dns_enabled", "total_record_count", "nodes" ], "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" }, "ClusterNetworkSettings": { "description": "Read-only cluster network state. Pool changes are performed on the control\nplane through `temps network setup-multi-node`, which enforces that no\nexisting node allocation can be stranded by an in-place edit.", "properties": { "allocation_count": { "format": "int64", "minimum": 0, "type": "integer" }, "compute_pool_cidr": { "type": "string" }, "locked": { "type": "boolean" }, "subnet_prefix_len": { "format": "int32", "minimum": 0, "type": "integer" } }, "required": [ "compute_pool_cidr", "subnet_prefix_len", "allocation_count", "locked" ], "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": [ { "$ref": "#/components/schemas/CommitInfo", "description": "Commit metadata when the requested SHA exists." }, { "type": "null" } ] }, "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" }, "Comparison": { "enum": [ "below", "above" ], "type": "string" }, "ComposePortMapping": { "description": "A Docker Compose service port mapping, reduced to the information the UI\nneeds to build a public route without confusing host and container ports.", "properties": { "protocol": { "description": "Transport protocol. Compose defaults to TCP.", "type": "string" }, "published": { "description": "Optional port published on the Docker host by Compose.", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "target": { "description": "Port inside the service container. Temps routes traffic to this port.", "format": "int32", "minimum": 0, "type": "integer" } }, "required": [ "target" ], "type": "object" }, "ComposePreviewProblemResponse": { "allOf": [ { "$ref": "#/components/schemas/ProblemDetails" }, { "properties": { "policy_check": { "oneOf": [ { "$ref": "#/components/schemas/ComposeSecurityCheck", "description": "The individual project security check an administrator may review." }, { "type": "null" } ] } }, "type": "object" } ], "description": "Problem Details returned when a Compose preview cannot be rendered." }, "ComposePreviewRequest": { "properties": { "branch": { "type": [ "string", "null" ] }, "composeOverride": { "type": [ "string", "null" ] }, "excludedServices": { "items": { "type": "string" }, "type": "array" }, "path": { "type": "string" }, "previewPolicy": { "$ref": "#/components/schemas/ComposeSecurityPolicy", "description": "Advisory preview only. Deployment reloads the saved project policy." } }, "required": [ "path" ], "type": "object" }, "ComposePreviewResponse": { "properties": { "disabledServices": { "items": { "type": "string" }, "type": "array" }, "effectiveCompose": { "description": "Effective user-controlled Compose YAML with sensitive values redacted.", "type": "string" }, "enabledServices": { "items": { "type": "string" }, "type": "array" }, "path": { "type": "string" }, "redactedValues": { "minimum": 0, "type": "integer" }, "repositoryId": { "format": "int32", "type": "integer" } }, "required": [ "repositoryId", "path", "effectiveCompose", "enabledServices", "disabledServices", "redactedValues" ], "type": "object" }, "ComposePublicPort": { "description": "A port that should be exposed publicly through the proxy for a compose service.", "properties": { "healthCheckPath": { "description": "Optional user override for the public health probe. When absent, Temps\nuses the path discovered from this service's Compose healthcheck.", "type": [ "string", "null" ] }, "port": { "description": "Container port to expose (e.g. 8123)", "format": "int32", "minimum": 0, "type": "integer" }, "published": { "description": "Optional port published on the Docker host by Compose. The proxy uses\nthis port when Temps runs on the host or reaches a remote node.", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "service": { "description": "Compose service name (e.g. \"web\", \"clickhouse\")", "type": "string" } }, "required": [ "service", "port" ], "type": "object" }, "ComposeSecurityCheck": { "enum": [ "extends", "include", "interpolation", "inline_services", "inline_sections", "inline_fields", "privileged", "docker_socket", "capabilities", "drop_capabilities", "security_options", "no_new_privileges", "devices", "device_rules", "gpu", "sysctls", "groups", "cgroup_parent", "runtime", "lifecycle_hooks", "provider", "container_name", "init", "host_network", "host_pid", "host_ipc", "host_uts", "host_cgroup", "host_user", "container_namespace", "network_mode", "external_networks", "network_names", "network_drivers", "network_options", "network_ipam", "external_links", "published_ports", "bind_mounts", "volume_drivers", "volume_network_filesystems", "volume_host_paths", "volume_options", "external_volumes", "volume_names", "volumes_from", "config_paths", "secret_paths", "external_configs", "external_secrets", "env_files", "label_files", "storage_options", "oom_killer", "service_shm", "aggregate_shm", "tmpfs", "ulimits", "pids", "memory", "logging", "blkio", "swap", "replicas", "remote_build", "build_context", "dockerfile", "build_privileged", "build_entitlements", "build_network", "build_ssh", "build_shm", "build_ulimits", "build_additional_contexts", "build_cache_from", "build_cache_to", "build_tags", "image_references", "build_image", "pull_policy" ], "type": "string" }, "ComposeSecurityCheckDefinition": { "properties": { "consequence": { "type": "string" }, "group": { "type": "string" }, "id": { "$ref": "#/components/schemas/ComposeSecurityCheck" }, "label": { "type": "string" } }, "required": [ "id", "group", "label", "consequence" ], "type": "object" }, "ComposeSecurityPolicy": { "additionalProperties": false, "properties": { "disabled_checks": { "items": { "$ref": "#/components/schemas/ComposeSecurityCheck" }, "type": "array", "uniqueItems": true } }, "type": "object" }, "ComposeSecurityResponse": { "properties": { "can_edit": { "type": "boolean" }, "checks": { "items": { "$ref": "#/components/schemas/ComposeSecurityCheckDefinition" }, "type": "array" }, "legacy_migration_pending": { "type": "boolean" }, "policy": { "$ref": "#/components/schemas/ComposeSecurityPolicy" } }, "required": [ "policy", "checks", "can_edit", "legacy_migration_pending" ], "type": "object" }, "ComposeServiceFamily": { "description": "The specific well-known service family a compose service's image matches,\nwhen it matches one Temps can deploy as a managed `external_services` row\ninstead. Drives the \"deploy this as a Temps-managed service\" recommendation\nin `GitSettings.tsx` and the deploy-log message — kept separate from\n`ComposeServiceSnapshot::looks_like_database` (which stays a plain bool)\nbecause that field only gates the unrelated \"may need elevated Linux\ncapabilities\" warning, and S3/MinIO images need this classification\nwithout tripping that warning.", "enum": [ "postgres", "mariadb", "mongodb", "redis", "s3" ], "type": "string" }, "ComposeServicePreviewResponse": { "properties": { "dependsOn": { "items": { "type": "string" }, "type": "array" }, "detectedServiceType": { "oneOf": [ { "$ref": "#/components/schemas/ComposeServiceFamily", "description": "Well-known managed-service family detected from the image, if any." }, { "type": "null" } ] }, "environmentVariables": { "description": "Environment variable names declared by this service. Values are\nintentionally omitted.", "items": { "type": "string" }, "type": "array" }, "image": { "type": [ "string", "null" ] }, "looksLikeDatabase": { "description": "True when the image looks like a well-known database engine\n(Postgres/MySQL/MariaDB/MongoDB/Redis and common forks) — a raw\ncompose service never becomes a Temps-managed `external_services` row,\nso it never gets backup/restore. Informational only.", "type": "boolean" }, "name": { "type": "string" }, "ports": { "description": "Ports declared by Compose. Route `target`, not `published`: the latter\nis only the optional host-side Docker port.", "items": { "$ref": "#/components/schemas/ComposePortMapping" }, "type": "array" } }, "required": [ "name", "dependsOn", "environmentVariables", "looksLikeDatabase", "ports" ], "type": "object" }, "ConnectionLimitSettings": { "description": "Per-upstream concurrent-connection limiting. Protects the proxy's own\nconnection/file-descriptor budget from a single slow or malicious\ncustomer upstream — independent of the request/idle timeouts in\n`RequestTimeoutSettings`, which bound how long a connection may stay\nopen, not how many may exist at once. See issue #646.", "properties": { "default_max_concurrent_connections": { "default": 0, "description": "Default max concurrent in-flight requests to a single\nproject/environment's upstream, used when the project/environment\nhasn't set its own `max_concurrent_connections` override. `0` (the\ndefault) means unlimited — matches the \"opt-in, never breaks an\nexisting app on upgrade\" philosophy already established for\n`RequestTimeoutSettings`.", "example": 200, "format": "int32", "minimum": 0, "type": "integer" } }, "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" }, "has_authenticated_credentials": { "description": "Whether this connection can make authenticated provider requests.\nThis exposes capability only; credential values are never serialized.", "type": "boolean" }, "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_sync_error": { "description": "Why the most recent repository sync failed or timed out; null once a\nsync succeeds.", "type": [ "string", "null" ] }, "last_sync_error_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", "has_authenticated_credentials", "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": [ { "$ref": "#/components/schemas/ResourceLimitsResponse", "description": "Resource limits" }, { "type": "null" } ] }, "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. The service's first public URL\nwhen it exposes several ports.", "type": [ "string", "null" ] }, "service_urls": { "description": "Every public URL of this compose service, one per public port.", "items": { "$ref": "#/components/schemas/ServicePublicUrl" }, "type": "array" }, "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" }, "ContainerHistoryEntry": { "description": "One container that has ever run for an environment — current or replaced\nby a later redeploy. `id` is the internal row ID to pass as the\n`container_id` path segment when calling the metrics/history endpoint for\nthis specific container generation (its docker `container_id` also works\nsince the history handler now resolves either).", "properties": { "container_id": { "type": "string" }, "container_name": { "type": "string" }, "deleted_at": { "example": "2025-10-12T12:15:47.609192Z", "type": [ "string", "null" ] }, "deployed_at": { "example": "2025-10-12T12:15:47.609192Z", "type": "string" }, "deployment_id": { "format": "int32", "type": "integer" }, "finished_at": { "example": "2025-10-12T12:15:47.609192Z", "type": [ "string", "null" ] }, "id": { "format": "int32", "type": "integer" }, "is_current": { "description": "True if this row is the environment's currently-active container\n(deleted_at is null) — false for containers replaced by a later\nredeploy.", "type": "boolean" }, "service_name": { "type": [ "string", "null" ] } }, "required": [ "id", "container_id", "container_name", "deployment_id", "deployed_at", "is_current" ], "type": "object" }, "ContainerHistoryListResponse": { "properties": { "containers": { "items": { "$ref": "#/components/schemas/ContainerHistoryEntry" }, "type": "array" }, "total_count": { "description": "Total number of container rows matching the filter, before `limit`\nwas applied — lets the client show \"20 of 627\".", "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "containers", "total_count" ], "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\").\nThe service's first public URL when it exposes several ports.", "type": [ "string", "null" ] }, "service_urls": { "description": "Every public URL of this compose service, one per public port.", "items": { "$ref": "#/components/schemas/ServicePublicUrl" }, "type": "array" }, "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": { "cache_mb": { "default": 2048, "description": "Disk budget, in MiB, for the collected-log read cache (`logs/cache`\nunder the data dir): recently read chunk blocks, block indexes and\nbloom filters kept locally so searches over object storage do not\nre-fetch them (ADR-046 §6). Applied within a minute of saving;\nshrinking evicts immediately.", "example": 2048, "format": "int32", "maximum": 1048576, "minimum": 64, "type": "integer" }, "head_buffer_mb": { "default": 8, "description": "Per-container cap, in MiB, on unsealed log lines held in memory (and\nthe WAL) before they are sealed into a chunk object. Larger buffers\nmean fewer, bigger chunks; smaller ones bound memory per container.", "example": 8, "format": "int32", "maximum": 256, "minimum": 1, "type": "integer" }, "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_id": { "description": "Decimal string form of this line's `line_id` — see [`LogSearchLine`].", "type": "string" }, "message": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "timestamp", "level", "message", "line_id", "is_match" ], "type": "object" }, "ContextLogsRequest": { "properties": { "container_id": { "type": "string" }, "line_id": { "description": "Decimal string form of the target line's `line_id`.", "type": "string" }, "lines": { "description": "Number of context lines before and after (default: 25, max 50)", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "timestamp": { "type": "string" } }, "required": [ "timestamp", "container_id", "line_id" ], "type": "object" }, "ContextLogsResponse": { "properties": { "lines": { "items": { "$ref": "#/components/schemas/ContextLine" }, "type": "array" }, "target_index": { "minimum": 0, "type": "integer" } }, "required": [ "lines", "target_index" ], "type": "object" }, "ContextWindowUsageResponse": { "properties": { "estimated": { "type": "boolean" }, "limit_tokens": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "model": { "type": [ "string", "null" ] }, "source": { "type": "string" }, "updated_at": { "type": "string" }, "used_tokens": { "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "used_tokens", "source", "estimated", "updated_at" ], "type": "object" }, "ContinuousArchiveSourceResponse": { "properties": { "continuous_archive_pinned_at": { "type": "string" }, "continuous_archive_s3_source_id": { "format": "int32", "type": "integer" }, "service_id": { "format": "int32", "type": "integer" } }, "required": [ "service_id", "continuous_archive_s3_source_id", "continuous_archive_pinned_at" ], "type": "object" }, "ControlApplicationWorkspaceRequest": { "additionalProperties": false, "properties": { "action": { "description": "restart, pause, resume, rebuild, snapshot, restore, or update_runtime", "type": "string" }, "confirm": { "description": "Must be true for update_runtime because compute is replaced.", "type": [ "boolean", "null" ] }, "label": { "type": [ "string", "null" ] }, "runtime": { "description": "Optional built-in flavor to select during update_runtime.", "type": [ "string", "null" ] }, "snapshot_id": { "type": [ "string", "null" ] } }, "required": [ "action" ], "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" }, "page": { "$ref": "#/components/schemas/ConversationMessagePageResponse" }, "pending_permission": { "oneOf": [ { "$ref": "#/components/schemas/PermissionRequest", "description": "A still-unresolved interactive permission request (ADR-038 Phase 2), if\none is pending on this conversation right now. The client renders this\nas a live, answerable `PermissionCard` — without it, a question that\narrived while the tab was away shows only as inert history text with no\nway to answer it." }, { "type": "null" } ] } }, "required": [ "messages", "page" ], "type": "object" } ] }, "ConversationDiagnosticMessageResponse": { "properties": { "content": { "type": "string" }, "cost_microcents": { "format": "int64", "type": [ "integer", "null" ] }, "created_at": { "type": "string" }, "metadata": {}, "role": { "type": "string" }, "tokens_in": { "format": "int32", "type": [ "integer", "null" ] }, "tokens_out": { "format": "int32", "type": [ "integer", "null" ] }, "truncated": { "type": "boolean" } }, "required": [ "role", "content", "created_at", "truncated" ], "type": "object" }, "ConversationDiagnosticResponse": { "properties": { "conversation": { "$ref": "#/components/schemas/ConversationDiagnosticRuntimeResponse" }, "message_limit": { "format": "int64", "minimum": 0, "type": "integer" }, "messages": { "items": { "$ref": "#/components/schemas/ConversationDiagnosticMessageResponse" }, "type": "array" }, "native_session": { "oneOf": [ { "$ref": "#/components/schemas/ConversationNativeDiagnosticResponse" }, { "type": "null" } ] }, "pending_permission": {}, "returned_message_count": { "minimum": 0, "type": "integer" }, "schema_version": { "format": "int32", "minimum": 0, "type": "integer" }, "source": { "$ref": "#/components/schemas/ConversationDiagnosticSourceResponse" }, "truncated": { "type": "boolean" } }, "required": [ "schema_version", "conversation", "source", "messages", "returned_message_count", "message_limit", "truncated" ], "type": "object" }, "ConversationDiagnosticRuntimeResponse": { "properties": { "active_turn_id": { "type": [ "string", "null" ] }, "context_id": { "type": "string" }, "context_type": { "type": "string" }, "context_usage": { "oneOf": [ { "$ref": "#/components/schemas/ContextWindowUsageResponse" }, { "type": "null" } ] }, "last_turn_id": { "type": [ "string", "null" ] }, "model": { "type": "string" }, "native_session_id": { "type": [ "string", "null" ] }, "permission_mode": { "type": "string" }, "provider": { "type": "string" }, "public_id": { "type": "string" }, "thinking_level": { "type": [ "string", "null" ] }, "turn_started_at": { "type": [ "string", "null" ] }, "turn_status": { "type": "string" } }, "required": [ "public_id", "context_type", "context_id", "provider", "model", "permission_mode", "turn_status" ], "type": "object" }, "ConversationDiagnosticSourceResponse": { "properties": { "native_session_note": { "type": "string" }, "native_session_status": { "type": "string" }, "normalized_history": { "type": "boolean" } }, "required": [ "normalized_history", "native_session_status", "native_session_note" ], "type": "object" }, "ConversationListScope": { "enum": [ "all", "global" ], "type": "string" }, "ConversationListStatus": { "enum": [ "active", "archived" ], "type": "string" }, "ConversationMessagePageResponse": { "properties": { "has_more": { "type": "boolean" }, "next_before": { "type": [ "string", "null" ] } }, "required": [ "has_more" ], "type": "object" }, "ConversationNativeDiagnosticResponse": { "properties": { "format": { "type": "string" }, "json": {}, "provider": { "type": "string" }, "session_id": { "type": "string" }, "truncated": { "type": "boolean" } }, "required": [ "provider", "session_id", "format", "json", "truncated" ], "type": "object" }, "ConversationResponse": { "properties": { "active_turn_id": { "type": [ "string", "null" ] }, "ai_model": { "type": "string" }, "ai_permission_mode": { "type": "string" }, "ai_provider": { "type": "string" }, "ai_thinking_level": { "type": [ "string", "null" ] }, "application_id": { "format": "int64", "type": [ "integer", "null" ] }, "context_id": { "type": "string" }, "context_type": { "type": "string" }, "context_usage": { "oneOf": [ { "$ref": "#/components/schemas/ContextWindowUsageResponse" }, { "type": "null" } ] }, "created_at": { "type": "string" }, "failure": { "oneOf": [ { "$ref": "#/components/schemas/ChatFailureResponse" }, { "type": "null" } ] }, "last_activity_at": { "type": "string" }, "project_id": { "format": "int32", "type": [ "integer", "null" ] }, "public_id": { "type": "string" }, "status": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "turn_started_at": { "type": [ "string", "null" ] }, "turn_status": { "description": "Server-authoritative lifecycle for the current/most recent turn.", "type": "string" } }, "required": [ "public_id", "context_type", "context_id", "status", "created_at", "last_activity_at", "ai_provider", "ai_model", "ai_permission_mode", "turn_status" ], "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": [ { "$ref": "#/components/schemas/ResourceFootprint", "description": "Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed." }, { "type": "null" } ] }, "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": [ { "$ref": "#/components/schemas/CloudProvider", "description": "Detected cloud provider (from node `providerID` prefixes)" }, { "type": "null" } ] }, "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" }, "CreatableServiceTypeRoute": { "enum": [ "mariadb", "mongodb", "postgres", "redis", "s3", "kv", "blob", "rustfs" ], "type": "string" }, "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" }, "CreateAnalyticsIngestKeyRequest": { "description": "Request body for minting a new ingest key.", "properties": { "allowed_origins": { "description": "Exact origins permitted to use this key from a browser. Omit or send an\nempty array to allow any origin.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "environment_id": { "description": "Scope the key to a single environment. Recommended: it lets Temps\nattribute ingested data to that environment's current deployment.\nOmit for a project-wide key.", "format": "int32", "type": [ "integer", "null" ] }, "name": { "description": "Operator-facing label. Defaults to \"Default ingest key\".", "type": [ "string", "null" ] }, "rate_limit_per_minute": { "description": "Requests per minute for this key. Omit for the 600/min default; send a\nnon-positive value for unlimited.", "format": "int32", "type": [ "integer", "null" ] } }, "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" }, "CreateApplicationConversationRequest": { "properties": { "ai_provider": { "description": "A registered development harness (for example `claude_cli`).\nApplication threads never inherit an API-gateway provider.", "type": [ "string", "null" ] } }, "type": "object" }, "CreateApplicationPreviewLinkRequest": { "properties": { "path": { "description": "Optional same-origin path to open after the preview grant is exchanged.", "type": [ "string", "null" ] }, "port": { "description": "The development server port detected or selected in the sandbox.", "format": "int32", "minimum": 0, "type": "integer" } }, "required": [ "port" ], "type": "object" }, "CreateApplicationProjectRequest": { "properties": { "exposed_port": { "format": "int32", "type": [ "integer", "null" ] }, "name": { "type": "string" }, "preset": { "description": "Deployment preset for the project. Defaults to `autopack`, which\ndetects the application runtime from the workspace source.", "type": [ "string", "null" ] } }, "required": [ "name" ], "type": "object" }, "CreateApplicationRequest": { "properties": { "description": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "project_ids": { "items": { "format": "int32", "type": "integer" }, "type": "array" }, "starter_project": { "oneOf": [ { "$ref": "#/components/schemas/CreateApplicationProjectRequest", "description": "Recommended default: create a deployable, Git-less starter project in\nthe application's persistent workspace." }, { "type": "null" } ] } }, "required": [ "name" ], "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" }, "service_ids": { "description": "External services to target when `target_all_services` is `false`.\nThe schedule and these memberships are created atomically, so an\nenabled schedule can never be observed without its requested targets.", "items": { "format": "int32", "type": "integer" }, "type": "array" }, "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 supplied in\n`service_ids` (or later attached through the schedule-services API).\nOmit to use the default.", "type": [ "boolean", "null" ] } }, "required": [ "name", "backup_type", "retention_period", "schedule_expression", "enabled", "tags" ], "type": "object" }, "CreateBatchRequest": { "allOf": [ { "description": "`output_expires_after` and any other field, forwarded unchanged.", "type": "object" }, { "properties": { "completion_window": { "description": "Currently only `24h`.", "type": "string" }, "endpoint": { "description": "Endpoint every request in the input file targets: `/v1/responses`,\n`/v1/chat/completions` or `/v1/embeddings`.", "type": "string" }, "input_file_id": { "description": "A file uploaded through `POST /ai/v1/files` by the same caller.", "type": "string" }, "metadata": { "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" }, "type": [ "object", "null" ] } }, "required": [ "input_file_id", "endpoint", "completion_window" ], "type": "object" } ], "description": "Request body of `POST /ai/v1/batches`." }, "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" }, "CreateBulkActivationJobRequest": { "description": "Body for `POST /bulk-jobs`.\n\nDeliberately one field. The plan is inside the token, so there is no project\nlist here to disagree with the one that was quoted.", "properties": { "plan_token": { "description": "The `plan_token` from a `POST /bulk-jobs/estimate` response.", "type": "string" } }, "required": [ "plan_token" ], "type": "object" }, "CreateCloudflareProviderRequest": { "properties": { "config": { "$ref": "#/components/schemas/CloudflareConfig" }, "enabled": { "type": [ "boolean", "null" ] }, "name": { "type": "string" } }, "required": [ "name", "config" ], "type": "object" }, "CreateConversationRequest": { "properties": { "ai_model": { "type": [ "string", "null" ] }, "ai_permission_mode": { "type": [ "string", "null" ] }, "ai_provider": { "description": "Provider pinned to this conversation. Omitted requests use the current\ninstance preference.", "type": [ "string", "null" ] }, "ai_thinking_level": { "type": [ "string", "null" ] }, "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" }, "CreateDeliveryProfileRequest": { "properties": { "bunny_api_key": { "type": [ "string", "null" ] }, "bunny_pull_zone_id": { "format": "int64", "type": [ "integer", "null" ] }, "name": { "type": "string" }, "provider_kind": { "$ref": "#/components/schemas/DeliveryProviderKind" } }, "required": [ "name", "provider_kind" ], "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": [ { "$ref": "#/components/schemas/ScalewayCredentialsRequest", "description": "Scaleway credentials (required if provider_type is scaleway)" }, { "type": "null" } ] }, "ses_credentials": { "oneOf": [ { "$ref": "#/components/schemas/SesCredentialsRequest", "description": "AWS SES credentials (required if provider_type is ses)" }, { "type": "null" } ] }, "smtp_credentials": { "oneOf": [ { "$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." }, { "type": "null" } ] }, "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": { "default": false, "description": "Include this environment variable in preview environments (default: false)", "type": "boolean" }, "is_secret": { "description": "When true the stored value is write-only: it is omitted from API\nresponses and cannot be revealed, even by an administrator. Updates\nthat omit the value preserve the existing ciphertext. The flag is\none-way — secret vars cannot be demoted 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": {}, "description": "Service-type-specific configuration. Read\n`GET /external-services/types/{service_type}/parameters` before creating\na service and provide every field its schema marks as required. Secret\nvalues that the schema describes as auto-generated may be omitted.", "propertyNames": { "type": "string" }, "type": "object" }, "project_id": { "description": "Optionally link the new service to this project as part of the same\nrequest. The caller must have write access to the target project. If\nlinking fails, Temps removes the newly created service so callers do\nnot have to recover an ambiguous half-created resource.", "format": "int32", "type": [ "integer", "null" ] }, "service_type": { "$ref": "#/components/schemas/CreatableServiceTypeRoute" }, "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" }, "CreateFacetRequest": { "description": "Request body for registering a new facet.", "properties": { "attribute_key": { "description": "The OTel attribute key to facet (e.g. `enduser.id`, `galachain.contract`).\nMust be non-empty, ≤200 characters, and not already registered.", "type": "string" } }, "required": [ "attribute_key" ], "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" }, "CreateGlobalConversationRequest": { "properties": { "ai_model": { "type": [ "string", "null" ] }, "ai_permission_mode": { "type": [ "string", "null" ] }, "ai_provider": { "description": "A registered development harness. Global operator chats run inside a\npersistent Temps-managed sandbox rather than on the host filesystem.", "type": [ "string", "null" ] }, "ai_thinking_level": { "type": [ "string", "null" ] } }, "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": "IPv4 or IPv6 address, in CIDR notation for ranges (e.g., \"192.168.1.1\",\n\"10.0.0.0/24\", \"2001:db8::1\", or \"2001:db8::/32\")", "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": { "description": "How often to probe, in seconds. Defaults to 60 when omitted.\n\n**Clamped, not rejected**: values below 30 are stored as 30 and\nnon-positive values as 60, and the created monitor comes back with the\nclamped value — so the response always reports the interval the\nscheduler will actually use.", "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" }, "CreateNodePairingRequest": { "description": "Start pairing a node.", "properties": { "address": { "description": "The node's public address, `ip` or `ip:port`. The control plane dials\nit on the mesh UDP port (or the port given).", "type": "string" }, "name": { "description": "Name the node registers under. Defaults to `worker-`.", "type": [ "string", "null" ] } }, "required": [ "address" ], "type": "object" }, "CreateNodePairingResponse": { "description": "A new pairing and the one command to run on the node. The command holds\na secret and is returned only here.", "properties": { "join_command": { "description": "Run this on the node, as root. It pipes the pairing code into `temps join --pair -`, so the code stays out of the process list and shell history.", "type": "string" }, "pairing": { "$ref": "#/components/schemas/NodePairingResponse" } }, "required": [ "pairing", "join_command" ], "type": "object" }, "CreateNotificationEmailProviderRequest": { "properties": { "config": { "$ref": "#/components/schemas/EmailConfig" }, "enabled": { "type": [ "boolean", "null" ] }, "name": { "type": "string" } }, "required": [ "name", "config" ], "type": "object" }, "CreateNotificationRouteRequest": { "properties": { "enabled": { "type": [ "boolean", "null" ] }, "max_severity": { "type": "string" }, "min_severity": { "type": "string" }, "name": { "type": "string" }, "provider_ids": { "items": { "format": "int32", "type": "integer" }, "type": "array" } }, "required": [ "name", "min_severity", "max_severity", "provider_ids" ], "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 three deploy modes:\n * **Native image service mode** — curated service templates deploy a\n digest-pinned container image and retain their template release identity,\n runtime configuration, and managed-service bindings.\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" }, "cloudflare_enabled": { "description": "Override the Cloudflare default for this new project.", "type": [ "boolean", "null" ] }, "command": { "description": "Optional image entrypoint arguments. An empty list explicitly uses the\nimage's own default command instead of the template command.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "cpu_limit": { "description": "CPU limit override in microcores. Zero means uncapped.", "format": "int32", "type": [ "integer", "null" ] }, "cpu_request": { "description": "CPU request override in microcores (1_000_000 = one CPU core).", "format": "int32", "type": [ "integer", "null" ] }, "delivery_provider": { "type": [ "string", "null" ] }, "environment_variables": { "description": "Environment variables to set (key-value pairs)", "items": { "$ref": "#/components/schemas/EnvVarInput" }, "type": "array" }, "exposed_port": { "description": "Public container port override.", "format": "int32", "type": [ "integer", "null" ] }, "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" ] }, "health_check_path": { "description": "Relative HTTP health-check path override.", "type": [ "string", "null" ] }, "image": { "description": "Optional prebuilt-image override. Curated template values remain the\ndefault when this is omitted. Accepted only for image templates.", "type": [ "string", "null" ] }, "memory_limit": { "description": "Memory limit override in MiB. Zero means uncapped.", "format": "int32", "type": [ "integer", "null" ] }, "memory_request": { "description": "Memory request override in MiB.", "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": { "deployment_error": { "description": "Actionable retry guidance when project creation succeeded but deployment\ndispatch did not. Internal queue errors are never exposed.", "type": [ "string", "null" ] }, "deployment_queued": { "description": "Whether the initial deployment was successfully queued. This is set for\nnative image service templates; Git-backed modes use their pipeline flow.", "type": [ "boolean", "null" ] }, "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" ] }, "cloudflare_enabled": { "description": "Override the instance default for this new project.", "type": [ "boolean", "null" ] }, "custom_domain": { "type": [ "string", "null" ] }, "delivery_provider": { "description": "Choose a delivery provider for this project. `none` disables the global default.", "type": [ "string", "null" ] }, "directory": { "type": "string" }, "environment_variables": { "description": "Environment variables to seed the default (production) environment with.\n\nAccepts objects — `{\"key\": \"API_KEY\", \"value\": \"sk-...\", \"is_secret\": true}`\n— or the legacy two-element form `[\"API_KEY\", \"sk-...\"]`, which implies\n`is_secret: false`.", "items": { "$ref": "#/components/schemas/ProjectEnvVarInput" }, "type": [ "array", "null" ] }, "expected_slug": { "description": "Optimistically reserved slug used by template creation to ensure the\npersisted project receives the URL shown during configuration.", "type": [ "string", "null" ] }, "exposed_port": { "description": "Explicit port exposed by the container.\n\nPriority order for port resolution:\n1. Environment-level exposed_port (explicit override)\n2. This project-level exposed_port (explicit override)\n3. Image EXPOSE directive (auto-detected from built image)\n4. Default: 3000\n\nSet this when the desired application port differs from the image's\nfirst EXPOSE directive (for example, an image exposing HTTP and HTTPS).", "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": [ { "$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```" }, { "type": "null" } ] }, "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" ], "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/` as a read-only mount, instead of as environment\nvariables, so they do not appear in `docker inspect`.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).", "properties": { "compose_services": { "description": "Docker Compose services allowed to read this secret, by compose\nservice name. Empty (the default) delivers it to every service in the\nstack, which is how secrets behaved before scoping existed.\n\nIgnored by non-Compose presets: those deploy a single container, which\nalways receives every secret in scope for its environment.", "items": { "type": "string" }, "type": "array" }, "environment_ids": { "items": { "format": "int32", "type": "integer" }, "type": "array" }, "include_in_preview": { "default": false, "description": "Include this secret in preview environments (default: false).", "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" }, "backing_service_id": { "description": "Managed RustFS/S3 service that supplies this destination. When set,\nschedules using this source can never target that service itself.", "format": "int32", "type": [ "integer", "null" ] }, "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" }, "from_snapshot": { "description": "Create the sandbox from a snapshot (ADR-037).\n\nMutually exclusive with `image`: if both are set the request fails\nwith 400. When set, the sandbox is created with the snapshotted\nfilesystem rather than a base image, giving users a reproducible\nstarting point.\n\nThe snapshot must be in `ready` status and belong to the calling user.", "type": [ "string", "null" ] }, "image": { "description": "Docker image override. `null` uses the platform default.", "type": [ "string", "null" ] }, "lifecycle": { "description": "Lifecycle class (ADR-036, temps-native): `\"ephemeral\"` (default) or\n`\"workspace\"`.\n\nA workspace is a long-lived development environment: it is still\nsuspended after `timeout_secs` of inactivity, but the next exec or\nfilesystem call wakes it transparently instead of returning 409, and\nnothing ever destroys it automatically. Use it for \"give me a place\nto work on this repo\"; leave it unset for throwaway sandboxes.", "type": [ "string", "null" ] }, "memory_limit_mb": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "name": { "type": [ "string", "null" ] }, "networkPolicy": {}, "node": { "description": "Node to create the sandbox on (ADR-048): a node name, a node id, or\n`control-plane` / `0` for the control plane. Omit to let Temps place\nit (the control plane when allowed, otherwise the allowed worker with\nthe fewest live sandboxes). The node must be allowed by the operator's\nsandbox placement settings and online; otherwise the request fails\nwith 422 — it never silently falls back to another node.", "example": "worker-1", "type": [ "string", "null" ] }, "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" ] }, "project_id": { "description": "Create the sandbox against a temps project (temps-native). The\nproject's connected repo and git credential seed the work dir when\nno explicit `source` is given, and the sandbox is attributed to the\nproject so it can be listed alongside it.\n\nRequires access to the project and `git_repositories:read` when Temps\nderives the source from the project. The same team/scope rules that\ngate every other project-scoped endpoint apply.", "format": "int32", "type": [ "integer", "null" ] }, "resources": { "oneOf": [ { "$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." }, { "type": "null" } ] }, "source": { "oneOf": [ { "$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." }, { "type": "null" } ] }, "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" }, "CreateSnapshotBody": { "description": "Request body for `POST /v1/sandboxes/{id}/snapshots`.", "properties": { "label": { "description": "Optional human-readable label for the snapshot.", "type": [ "string", "null" ] } }, "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" }, "CreateThreadArtifactRequest": { "properties": { "kind": { "type": "string" }, "payload": {}, "title": { "type": [ "string", "null" ] } }, "required": [ "kind", "payload" ], "type": "object" }, "CreateUserRequest": { "properties": { "email": { "type": [ "string", "null" ] }, "must_change_password": { "type": "boolean" }, "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": [ { "$ref": "#/components/schemas/DomainEnvironmentResponse" }, { "type": "null" } ] }, "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" }, "DatabaseProvisioningMode": { "description": "Controls which logical database a deployment receives through a\nproject-to-service link.", "enum": [ "project", "project_environment", "custom" ], "type": "string" }, "DeferredWalGeneration": { "properties": { "bytes": { "format": "int64", "minimum": 0, "type": "integer" }, "deferred_at": { "format": "date-time", "type": [ "string", "null" ] }, "file_name": { "type": "string" }, "reason": { "description": "What recovery could not read and what it did with the rest.", "type": [ "string", "null" ] } }, "required": [ "file_name", "bytes" ], "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" }, "DeliveryCapabilityResponse": { "properties": { "configured": { "type": "boolean" }, "name": { "type": "string" }, "provider_kind": { "$ref": "#/components/schemas/DeliveryProviderKind" }, "requirements": { "items": { "type": "string" }, "type": "array" }, "setup_path": { "type": [ "string", "null" ] }, "supported": { "type": "boolean" } }, "required": [ "provider_kind", "name", "supported", "configured", "requirements" ], "type": "object" }, "DeliveryProfilePage": { "description": "One page of delivery profiles (`GET /delivery-profiles`).", "properties": { "items": { "items": { "$ref": "#/components/schemas/DeliveryProfileResponse" }, "type": "array" }, "page": { "description": "1-based number of this page.", "format": "int64", "minimum": 0, "type": "integer" }, "page_size": { "description": "Page size applied to the request, after clamping to 1..=100.", "format": "int64", "minimum": 0, "type": "integer" }, "total": { "description": "Number of delivery profiles across all pages.", "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "items", "total", "page", "page_size" ], "type": "object" }, "DeliveryProfileResponse": { "properties": { "bunny_hostname": { "description": "Bunny system CDN hostname. Omitted (`null`) for callers without DNS\nprovider read access.", "type": [ "string", "null" ] }, "bunny_pull_zone_id": { "description": "Bunny Pull Zone ID. Omitted (`null`) for callers without DNS provider\nread access, who only see the profile's name and kind.", "format": "int64", "type": [ "integer", "null" ] }, "created_at": { "format": "date-time", "type": "string" }, "id": { "format": "int32", "type": "integer" }, "name": { "type": "string" }, "provider_kind": { "$ref": "#/components/schemas/DeliveryProviderKind" }, "updated_at": { "format": "date-time", "type": "string" } }, "required": [ "id", "name", "provider_kind", "created_at", "updated_at" ], "type": "object" }, "DeliveryProviderKind": { "enum": [ "direct", "cloudflare", "bunny" ], "type": "string" }, "DeliveryRecordPlan": { "properties": { "expected_existing_record": { "oneOf": [ { "$ref": "#/components/schemas/DnsRecord", "description": "The record live at the provider when the preview was taken. Apply\nrefuses if the provider no longer holds exactly this record." }, { "type": "null" } ] }, "name": { "type": "string" }, "ownership_status": { "type": "string" }, "proxied": { "type": "boolean" }, "record_type": { "$ref": "#/components/schemas/DnsRecordType" }, "requires_adoption": { "type": "boolean" }, "value": { "type": "string" } }, "required": [ "name", "record_type", "value", "proxied", "ownership_status", "requires_adoption" ], "type": "object" }, "DeliveryRecordRequirement": { "properties": { "content": { "$ref": "#/components/schemas/DnsRecordContent" }, "name": { "type": "string" }, "proxied": { "type": "boolean" }, "record_type": { "$ref": "#/components/schemas/DnsRecordType" }, "ttl": { "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "value": { "type": "string" } }, "required": [ "name", "record_type", "content", "value", "proxied" ], "type": "object" }, "DeliveryRequirements": { "properties": { "origin_tls": { "$ref": "#/components/schemas/OriginTlsPolicy" }, "record": { "$ref": "#/components/schemas/DeliveryRecordRequirement" }, "warnings": { "items": { "type": "string" }, "type": "array" } }, "required": [ "record", "origin_tls", "warnings" ], "type": "object" }, "DeliveryRoutingPlan": { "properties": { "custom_domain_id": { "format": "int32", "type": [ "integer", "null" ] }, "will_create_custom_domain": { "type": "boolean" } }, "required": [ "will_create_custom_domain" ], "type": "object" }, "DeployApplicationProjectRequest": { "properties": { "environment_id": { "description": "Target environment. Omit to use production, then the project's oldest\nactive environment as a fallback.", "format": "int32", "type": [ "integer", "null" ] } }, "type": "object" }, "DeployFromImageRequest": { "properties": { "claim_local": { "description": "Claim an image already present in the platform host's Docker daemon.\nTemps retags it into a generated project-owned namespace and records\nits immutable image ID. Never set this for a registry image.", "type": "boolean" }, "command": { "description": "Optional container command override. Each entry is passed directly as\none argv element; no shell parsing or interpolation is performed.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "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": "Deprecated display hint retained for wire compatibility. Temps always\ngenerates the actual project-scoped internal image reference.", "example": "myapp:v1.0", "type": [ "string", "null" ] }, "upload_request_id": { "description": "Client-generated UUID identifying this upload attempt. When a\ndeployment already exists for this project, environment, and ID, that\ndeployment is returned as-is instead of importing and deploying the\nimage again — this makes a client retry after a lost response safe.\nCallers that omit it get no such protection (each call always creates\na new deployment), so the CLI always sends one.", "example": "9b1f7a4e-6e3e-4d9b-8c34-5b6b6a6d7e21", "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" ] }, "healthCheckTimeoutSeconds": { "description": "How long, in seconds, a new container may take to start and pass its\nreadiness check before the deployment fails. Covers apps that boot\nslowly (migrations, JIT warm-up, large model loads). `None` = the\nplatform default ([`DEFAULT_HEALTH_CHECK_TIMEOUT_SECONDS`]); valid\noverrides are [`MIN_HEALTH_CHECK_TIMEOUT_SECONDS`]..=\n[`MAX_HEALTH_CHECK_TIMEOUT_SECONDS`]. Environments inherit the project\nvalue and may override it.", "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" }, "maxConcurrentConnections": { "description": "Override for the proxy's cap on concurrent in-flight requests to this\nproject/environment's upstream, independent of the timeout overrides\nabove. `None` = inherit the global\n`connection_limits.default_max_concurrent_connections`. `Some(0)`\nexplicitly forces \"unlimited\" for this project/environment, overriding\na nonzero global default. `Some(n)` for `n > 0` sets an explicit cap —\nthere is no global ceiling clamp here (unlike the timeout settings):\nan operator who has explicitly set a per-project value has made a\ndeliberate choice and the platform should respect it.", "format": "int32", "type": [ "integer", "null" ] }, "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" }, "requestTimeoutSeconds": { "description": "Override for the proxy's upstream timeout on regular (non-streaming)\nHTTP requests to this project/environment, in seconds.\n`None` = inherit the global `request_timeouts.default_http_timeout_seconds`\n(which itself defaults to \"no timeout\"). `Some(0)` explicitly forces\n\"no timeout\" for this project/environment, overriding a nonzero\nglobal default. `Some(n)` for `n > 0` sets an explicit timeout,\nalways clamped to the global hard ceiling\n(`request_timeouts.max_request_timeout_seconds`) at resolution time.", "format": "int32", "type": [ "integer", "null" ] }, "security": { "oneOf": [ { "$ref": "#/components/schemas/SecurityConfig", "description": "Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)" }, { "type": "null" } ] }, "sessionRecordingEnabled": { "description": "Enable session recording for analytics", "type": "boolean" }, "sseIdleTimeoutSeconds": { "description": "Override for the proxy's idle timeout on Server-Sent Events streams to\nthis project/environment, in seconds. `None` = inherit the global\n`request_timeouts.default_sse_idle_timeout_seconds`. `Some(0)`\nexplicitly forces \"no timeout\". `Some(n)` for `n > 0` is clamped to\nthe global hard ceiling at resolution time.", "format": "int32", "type": [ "integer", "null" ] }, "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" }, "websocketIdleTimeoutSeconds": { "description": "Override for the proxy's idle timeout on WebSocket connections to this\nproject/environment, in seconds. `None` = inherit the global\n`request_timeouts.default_websocket_idle_timeout_seconds`. `Some(0)`\nexplicitly forces \"no timeout\". `Some(n)` for `n > 0` is clamped to\nthe global hard ceiling at resolution time.", "format": "int32", "type": [ "integer", "null" ] } }, "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": [ { "$ref": "#/components/schemas/BuildConfiguration", "description": "Build configuration (if building from source)" }, { "type": "null" } ] }, "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": [ { "$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." }, { "type": "null" } ] }, "health_check": { "oneOf": [ { "$ref": "#/components/schemas/HealthCheckConfiguration", "description": "Health check configuration" }, { "type": "null" } ] }, "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" }, "service_urls": { "description": "Public URLs of this environment's Docker Compose services, one per\nconfigured public port. Empty for non-Compose projects.", "items": { "$ref": "#/components/schemas/ServicePublicUrl" }, "type": "array" }, "slug": { "type": "string" } }, "required": [ "id", "name", "slug", "domains" ], "type": "object" }, "DeploymentFailureCode": { "description": "Allowlisted failure codes. Wire values are `snake_case` and stable; add new\nvariants rather than renaming existing ones.", "enum": [ "out_of_memory", "disk_exhausted", "timeout", "health_check_failed", "repository_authentication", "repository_not_found", "repository_clone", "dns_resolution", "network_connection", "dependency_lockfile_out_of_sync", "dependency_resolution", "dependency_download", "runtime_version_unsupported", "missing_build_script", "compile_error", "dockerfile_invalid", "base_image_pull", "image_missing", "static_output_missing", "port_unavailable", "permission_denied", "invalid_configuration", "container_start", "build_error", "platform_internal", "cancelled", "build_timeout", "source_timeout", "image_pull_timeout", "health_check_timeout", "app_not_listening", "container_exited", "image_not_found", "registry_authentication", "registry_rate_limited", "image_platform_mismatch", "compose_file_invalid", "compose_variable_missing", "compose_policy_rejected", "compose_build_failed", "compose_up_failed", "compose_unavailable", "volume_mount", "route_activation", "unknown" ], "type": "string" }, "DeploymentFailureInfo": { "description": "API view of a failed deployment's classification.", "properties": { "classifier_version": { "description": "Version of the classifier that produced this view.", "format": "int32", "minimum": 0, "type": "integer" }, "code": { "$ref": "#/components/schemas/DeploymentFailureCode", "description": "Allowlisted failure code." }, "failed_job": { "description": "Pipeline job that failed (e.g. `build_image`, `deploy_compose`).", "type": [ "string", "null" ] }, "remediation": { "description": "Concrete, actionable fix.", "type": "string" }, "settings_section": { "oneOf": [ { "$ref": "#/components/schemas/FailureSettingsSection", "description": "Settings surface that fixes it, when one exists." }, { "type": "null" } ] }, "stage": { "$ref": "#/components/schemas/DeploymentFailureStage", "description": "Pipeline stage the deployment failed in." }, "timeout_elapsed_seconds": { "description": "How long the timed-out step ran, in seconds, when the reason states it.", "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "timeout_limit_seconds": { "description": "Time limit that was hit, in seconds, when the failure is a timeout and\nthe reason states it.", "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "title": { "description": "Short human title, e.g. \"Image tag not found\".", "type": "string" } }, "required": [ "stage", "code", "title", "remediation", "classifier_version" ], "type": "object" }, "DeploymentFailureStage": { "description": "The pipeline stage a deployment failed in.", "enum": [ "source", "configuration", "dependency_install", "build", "image", "deploy", "runtime", "health_check", "resource", "platform", "unknown" ], "type": "string" }, "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" ] }, "command": { "description": "Command passed to a prebuilt image entrypoint. Stored in deployment\nmetadata so redeploy, rollback, and node failover reproduce the exact\nworkload rather than falling back to the image default.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "deploymentDurationMs": { "description": "Deployment duration in milliseconds", "format": "int64", "type": [ "integer", "null" ] }, "deploymentSourceType": { "oneOf": [ { "$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" }, { "type": "null" } ] }, "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": [ { "$ref": "#/components/schemas/GitPushEvent", "description": "Git push event that triggered this deployment (if from webhook)" }, { "type": "null" } ] }, "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" ] }, "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": [ "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": [ { "$ref": "#/components/schemas/DeploymentConfigSnapshot", "description": "Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)" }, { "type": "null" } ] }, "environment": { "$ref": "#/components/schemas/DeploymentEnvironmentResponse" }, "environment_id": { "format": "int32", "type": "integer" }, "failure": { "oneOf": [ { "$ref": "#/components/schemas/DeploymentFailureInfo", "description": "Classified cause of a failed deployment: the stage it failed in, a\nstable failure code, and a concrete fix. Present only when `status` is\n`failed` and a failure reason was recorded. Derived from\n`cancelled_reason` at read time, so older deployments are classified\nby the current classifier too." }, { "type": "null" } ] }, "finished_at": { "format": "int64", "type": [ "integer", "null" ] }, "id": { "format": "int32", "type": "integer" }, "is_current": { "type": "boolean" }, "metadata": { "oneOf": [ { "$ref": "#/components/schemas/DeploymentMetadata", "description": "Deployment metadata (build info, git event, etc.)" }, { "type": "null" } ] }, "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." } ] }, "DetectionEvidence": { "enum": [ "value_pattern", "variable_name" ], "type": "string" }, "DetectionView": { "properties": { "candidates": { "items": { "$ref": "#/components/schemas/Candidate" }, "type": "array" }, "detection_rule_count": { "minimum": 0, "type": "integer" }, "env_var_id": { "format": "int32", "type": "integer" }, "local_artifacts": { "description": "Expiring items a local check would read. Labels and dates only, never\nvalues or token claims.", "items": { "$ref": "#/components/schemas/ExpiringArtifact" }, "type": "array" } }, "required": [ "env_var_id", "candidates", "local_artifacts", "detection_rule_count" ], "type": "object" }, "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": { "api_key": { "type": "string" }, "type": { "enum": [ "bunny" ], "type": "string" } }, "required": [ "api_key", "type" ], "type": "object" }, { "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", "bunny", "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 generated-hostname sync would make, or\nmade.", "properties": { "action": { "description": "`\"create\"`, `\"update\"` or `\"delete\"`; `\"adopt\"` for a record the user\nconfirmed adopting (`value` is its value before any update);\n`\"skip\"` for a hostname the user chose to leave untouched;\n`\"conflict\"` for one nobody decided on yet (see `conflicts`), which\nmakes an apply change nothing; `\"restore\"` for a record written back\nafter its replacement failed.", "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" }, "DnsRecordConflict": { "description": "A generated hostname whose record the sync may not write without the\nuser's decision: adopt the record at its name (when `adoptable`), or skip\nthe hostname.", "properties": { "adoptable": { "description": "Whether the record at this name can be adopted. Records another Temps\nworkflow or installation owns, and ambiguous states, cannot: skip\nthem, or resolve them at the provider and preview again.", "type": "boolean" }, "current_proxied": { "description": "Whether that record is proxied.", "type": [ "boolean", "null" ] }, "current_value": { "description": "Value of the record at this name and type, when there is exactly one.", "example": "203.0.113.10", "type": [ "string", "null" ] }, "name": { "description": "Fully-qualified generated hostname.", "example": "pr-12.preview.example.com", "type": "string" }, "proxied": { "description": "Whether the sync would write the record proxied.", "type": "boolean" }, "reason": { "description": "Why the sync may not write the record, and what resolves it.", "type": "string" }, "record_type": { "description": "Record type the sync publishes the hostname as.", "example": "A", "type": "string" }, "revision": { "description": "Identifies what this preview showed about the conflict. Send it with\nthe adopt or skip decision: the apply refuses a decision whose\nconflict changed after the preview (the record's value, proxy status\nor owner, a record next to it, or the value the sync would write).", "example": "9f2c4e1ab3d5f6071829304a5b6c7d8e9f0a1b2c3d4e5f60718293a4b5c6d7e8", "type": "string" }, "value": { "description": "Value the sync would write.", "example": "203.0.113.10", "type": "string" } }, "required": [ "name", "record_type", "value", "proxied", "reason", "adoptable", "revision" ], "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" }, "DnsRecordType": { "description": "DNS record types", "enum": [ "A", "AAAA", "CNAME", "TXT", "MX", "NS", "SRV", "CAA", "PTR" ], "type": "string" }, "DnsResolverHeartbeat": { "description": "Wire DTO for [`HeartbeatApiRequest::dns_resolver`]. Mirrors\n`temps_agent::network_sync::DnsResolverHeartbeat` field-for-field, but\ndeclared separately rather than shared: the agent and control-plane\ncrates don't depend on each other (the agent avoids pulling in\n`temps-deployments`' sea-orm dependency tree), matching the existing\n`WirePeerListResponse` pattern in `temps-agent::network_sync`.", "properties": { "consecutive_sync_failures": { "format": "int32", "minimum": 0, "type": "integer" }, "last_sync_error": { "description": "Most recent resolver-related error: a sync tick failure, or (when the\nresolver never started at all) the startup error itself.", "type": [ "string", "null" ] }, "last_sync_success_at": { "format": "date-time", "type": [ "string", "null" ] }, "record_count": { "format": "int64", "type": "integer" }, "running": { "description": "`false` when cluster DNS is disabled on the control plane, the\nresolver failed to start, or it was shut down. `true` only while a\nresolver handle currently exists and cluster DNS is enabled.", "type": "boolean" }, "tasks_alive": { "description": "`false` means the resolver's sync or DNS server task crashed. Only\nmeaningful when `running`.", "type": "boolean" } }, "type": "object" }, "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" }, "relaxedCapabilityServices": { "description": "Services granted the limited startup capability profile after explicit approval.", "items": { "type": "string" }, "type": "array" } }, "type": "object" }, "DockerDiskUsage": { "description": "Result of `docker system df` for the control-plane host.", "properties": { "api_version": { "description": "Docker API version the daemon answered with, when it reported one\n(`Api-Version` header). Useful when a category shows `null`\nreclaimable bytes.", "type": [ "string", "null" ] }, "build_cache": { "$ref": "#/components/schemas/DockerDiskUsageCategory" }, "collected_at": { "description": "When this snapshot was taken (ISO 8601, UTC).", "type": "string" }, "containers": { "$ref": "#/components/schemas/DockerDiskUsageCategory" }, "images": { "$ref": "#/components/schemas/DockerDiskUsageCategory" }, "total_bytes": { "description": "Sum of the four category sizes.", "format": "int64", "type": "integer" }, "volumes": { "$ref": "#/components/schemas/DockerDiskUsageCategory" } }, "required": [ "images", "containers", "volumes", "build_cache", "total_bytes", "collected_at" ], "type": "object" }, "DockerDiskUsageCategory": { "description": "One slice of the Docker disk-usage donut.", "properties": { "active_count": { "description": "Objects currently in use (images referenced by a container, running\ncontainers, mounted volumes, in-use cache records).", "format": "int64", "type": "integer" }, "reclaimable_bytes": { "description": "Bytes `docker system prune` could free from this category. `null`\nwhen the daemon is older than API 1.52 and does not report it.", "format": "int64", "type": [ "integer", "null" ] }, "size_bytes": { "description": "Bytes on disk attributed to this category.", "format": "int64", "type": "integer" }, "total_count": { "description": "Number of objects in this category (all images, all containers, …).", "format": "int64", "type": "integer" } }, "required": [ "total_count", "active_count", "size_bytes" ], "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" }, "DockerSocketCapability": { "description": "Where a project is granted host Docker access, published on the project\nresponse so the console can render a badge (granted) or an onboarding state\n(not granted) instead of the feature being invisible.\n\nDeliberately read-only. The grant is host policy; there is no write path,\nand an API that could set it would be one step from host root.", "properties": { "granted": { "description": "Whether any host grants this project `/var/run/docker.sock`.", "type": "boolean" }, "nodes": { "description": "Hosts that grant it: worker node names, plus `control-plane` when this\ncontrol plane's own environment names the project. Empty when not\ngranted.", "example": [ "control-plane", "worker-1" ], "items": { "type": "string" }, "type": "array" }, "reason": { "description": "Why it is not granted, when `granted` is false. Names the exact\nvariable, value and processes, because the operator is debugging alone.", "type": [ "string", "null" ] }, "setup_path": { "description": "Console path that shows the hosts this could be set on.", "type": [ "string", "null" ] } }, "required": [ "granted", "nodes" ], "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" ] }, "imageRuntime": { "oneOf": [ { "$ref": "#/components/schemas/ImageRuntimeConfig", "description": "Durable runtime selected for a curated single-container image template." }, { "type": "null" } ] }, "variant": { "oneOf": [ { "$ref": "#/components/schemas/DockerfileVariant", "description": "Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset." }, { "type": "null" } ] } }, "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" }, "DomainDeliveryBindingPage": { "description": "One page of a project's domain delivery bindings\n(`GET /projects/{project_id}/domain-delivery-bindings`).", "properties": { "items": { "items": { "$ref": "#/components/schemas/DomainDeliveryBindingResponse" }, "type": "array" }, "page": { "description": "1-based number of this page.", "format": "int64", "minimum": 0, "type": "integer" }, "page_size": { "description": "Page size applied to the request, after clamping to 1..=100.", "format": "int64", "minimum": 0, "type": "integer" }, "total": { "description": "Number of the project's bindings across all pages.", "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "items", "total", "page", "page_size" ], "type": "object" }, "DomainDeliveryBindingResponse": { "properties": { "applied_at": { "format": "date-time", "type": "string" }, "bunny_hostname_owned": { "description": "Whether Temps added this hostname to the Bunny Pull Zone. Only then\ndoes removing the binding also detach the hostname, and its edge\ncertificate, from the Pull Zone. `false` when the hostname was already\non the Pull Zone before Temps set up delivery: removal leaves it\nattached. Always `false` for Cloudflare and direct bindings.", "type": "boolean" }, "created_at": { "format": "date-time", "type": "string" }, "custom_domain_id": { "format": "int32", "type": "integer" }, "delivery_profile_id": { "format": "int32", "type": "integer" }, "delivery_profile_name": { "type": "string" }, "dns_provider_id": { "format": "int32", "type": "integer" }, "environment_id": { "format": "int32", "type": "integer" }, "hostname": { "type": "string" }, "id": { "format": "int32", "type": "integer" }, "last_error": { "type": [ "string", "null" ] }, "origin_target": { "type": "string" }, "profile_source": { "type": "string" }, "project_id": { "format": "int32", "type": "integer" }, "provider_kind": { "$ref": "#/components/schemas/DeliveryProviderKind" }, "proxied": { "type": "boolean" }, "record_type": { "$ref": "#/components/schemas/DnsRecordType" }, "status": { "type": "string" }, "updated_at": { "format": "date-time", "type": "string" }, "zone": { "type": "string" } }, "required": [ "id", "hostname", "project_id", "environment_id", "custom_domain_id", "delivery_profile_id", "delivery_profile_name", "profile_source", "provider_kind", "dns_provider_id", "zone", "origin_target", "record_type", "proxied", "bunny_hostname_owned", "status", "applied_at", "created_at", "updated_at" ], "type": "object" }, "DomainDeliveryPreviewResponse": { "properties": { "expires_at": { "format": "date-time", "type": "string" }, "origin_tls": { "$ref": "#/components/schemas/OriginTlsPolicy" }, "preview_id": { "type": "string" }, "profile_id": { "format": "int32", "type": "integer" }, "profile_source": { "type": "string" }, "provider_kind": { "$ref": "#/components/schemas/DeliveryProviderKind" }, "record": { "$ref": "#/components/schemas/DeliveryRecordPlan" }, "routing": { "$ref": "#/components/schemas/DeliveryRoutingPlan" }, "warnings": { "items": { "type": "string" }, "type": "array" } }, "required": [ "preview_id", "expires_at", "profile_id", "profile_source", "provider_kind", "origin_tls", "record", "routing", "warnings" ], "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 source node is empty and safe to remove. Replacement\ndeployments may still be converging asynchronously on other nodes.", "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" }, "remaining_sandboxes": { "description": "Sandboxes (any owner) still on this node. Draining does not move\nsandboxes; evict them before removing the node (ADR-048).", "format": "int64", "minimum": 0, "type": "integer" }, "status": { "type": "string" } }, "required": [ "node_id", "node_name", "status", "remaining_containers", "remaining_sandboxes", "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": { "composePath": { "type": [ "string", "null" ] }, "confidence": { "type": "string" }, "directory": { "type": "string" }, "dockerfilePath": { "description": "Repository-root-relative path to the Dockerfile, when it does not\nlive directly under `{directory}/Dockerfile` (e.g. `docker/Dockerfile`\nrolled up to a `directory` of `\".\"`). `None` for a Dockerfile located\ndirectly at `{directory}/Dockerfile` and for every non-Dockerfile\npreset.", "type": [ "string", "null" ] }, "isStatic": { "type": "boolean" }, "label": { "type": "string" }, "preset": { "type": "string" }, "reason": { "type": "string" } }, "required": [ "directory", "preset", "label", "confidence", "reason", "isStatic" ], "type": "object" }, "EligibleGitRepositoryResponse": { "properties": { "accountName": { "type": "string" }, "connectionId": { "format": "int32", "type": "integer" }, "fullName": { "type": "string" }, "private": { "type": "boolean" }, "repositoryId": { "format": "int32", "type": "integer" }, "repositoryUrl": { "type": "string" } }, "required": [ "connectionId", "repositoryId", "accountName", "fullName", "repositoryUrl", "private" ], "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" }, "delivery_unknown": { "description": "Emails whose provider accepted/rejected outcome could not be determined", "format": "int64", "minimum": 0, "type": "integer" }, "failed": { "format": "int64", "minimum": 0, "type": "integer" }, "queued": { "format": "int64", "minimum": 0, "type": "integer" }, "sending": { "description": "Emails currently owned by an active provider delivery attempt", "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", "sending", "delivery_unknown" ], "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": "rustfs/rustfs:1.0.0-rc.5", "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" }, "EnableWireguardMeshRequest": { "description": "Body of `POST /nodes/wireguard`. Both fields keep their current value\nwhen omitted; neither can change once a node is on the mesh.", "properties": { "cidr": { "description": "Mesh address pool (private IPv4, clear of the compute pool).", "type": [ "string", "null" ] }, "listen_port": { "description": "UDP port the mesh listens on.", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "node_api_port": { "description": "TCP port nodes reach the control plane's API on over the mesh.\nDefaults to the mesh port number.", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] } }, "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": { "description": "Attributes to attach to the visitor. Top-level keys are merged into the\nvisitor's stored `custom_data`; a key whose value is `null` removes that\nkey. Deployment tokens may send at most 32 keys and 8 KB.", "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" }, "EnrollCloudRequest": { "properties": { "enrollment_code": { "example": "ABCD-EFGH", "minLength": 1, "type": "string" } }, "required": [ "enrollment_code" ], "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" }, "EnvExampleVariable": { "description": "A single environment variable parsed from a detected env-example file", "properties": { "default_value": { "description": "Placeholder/default value as written in the file (may be empty)", "type": "string" }, "description": { "description": "Description derived from a `# comment` immediately preceding the\nvariable in the file, if any", "type": [ "string", "null" ] }, "key": { "description": "Variable name (e.g. \"DATABASE_URL\")", "type": "string" } }, "required": [ "key", "default_value" ], "type": "object" }, "EnvExampleVariableResponse": { "properties": { "defaultValue": { "description": "Placeholder/default value as written in the file (may be empty)", "type": "string" }, "description": { "description": "Description derived from a `# comment` immediately preceding the\nvariable in the file, if any", "type": [ "string", "null" ] }, "key": { "description": "Variable name (e.g. \"DATABASE_URL\")", "type": "string" } }, "required": [ "key", "defaultValue" ], "type": "object" }, "EnvVarInput": { "description": "Input for environment variable", "properties": { "is_secret": { "description": "Mark the variable as a secret. Secret values are encrypted at rest,\nmasked in list responses, and revealable only through an audited,\npermission-checked endpoint. Defaults to `false`.", "type": "boolean" }, "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" }, "EnvVarTemplate": { "description": "Environment variable template definition", "properties": { "default": { "description": "Default value if not provided by user", "type": [ "string", "null" ] }, "default_generator": { "description": "Frontend-side generator for the default value. Recognised values:\n`app_url` (https://{repo}.{base_domain}), `random_secret` (32-byte base64),\n`random_hex_32` (32-byte hex). Unknown values are ignored client-side.", "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" }, "secret": { "description": "Explicit sensitivity classification for credentials whose names do not\nmatch the conservative built-in heuristic.", "type": "boolean" } }, "required": [ "name" ], "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" }, "secret": { "description": "Whether values must use the protected secret reveal path.", "type": "boolean" } }, "required": [ "name", "required", "secret" ], "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" }, "EnvironmentDeliveryOverride": { "properties": { "environment_id": { "format": "int32", "type": "integer" }, "profile_id": { "format": "int32", "type": [ "integer", "null" ] } }, "required": [ "environment_id" ], "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": [ { "$ref": "#/components/schemas/DeploymentConfig", "description": "Deployment configuration for this environment (overrides project-level config)" }, { "type": "null" } ] }, "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 stored value is write-only. Marked secrets always have\n`value: None` in API responses and cannot be revealed.", "type": "boolean" }, "key": { "type": "string" }, "updated_at": { "format": "int64", "type": "integer" }, "value": { "description": "Plaintext for regular variables in create/update responses, or `\"***\"`\nin list responses. Always `None` for marked secrets. Only regular\nvariables can be read through the audited per-variable reveal endpoint.", "type": [ "string", "null" ] } }, "required": [ "id", "key", "created_at", "updated_at", "environments", "include_in_preview", "is_secret" ], "type": "object" }, "EnvironmentVariableValueResponse": { "properties": { "value": { "description": "Plaintext for a regular manual or integration-sourced variable.\nMarked secret manual variables never produce this response.", "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" }, "ErrorGroupDeploymentResponse": { "properties": { "branch": { "type": [ "string", "null" ] }, "commit_hash": { "type": [ "string", "null" ] }, "commit_message": { "type": [ "string", "null" ] }, "id": { "format": "int32", "type": "integer" } }, "required": [ "id" ], "type": "object" }, "ErrorGroupResponse": { "properties": { "affected_users": { "description": "Count of distinct affected visitors/users within the requested time window.\nPresent only when `start_date` and `end_date` were supplied on the list request.", "format": "int64", "type": [ "integer", "null" ] }, "assigned_to": { "type": [ "string", "null" ] }, "created_at": { "type": "string" }, "deployment": { "oneOf": [ { "$ref": "#/components/schemas/ErrorGroupDeploymentResponse", "description": "The deployment this group's `deployment_id` points to, resolved to its commit info.\n`None` when the group has no linked deployment." }, { "type": "null" } ] }, "deployment_id": { "format": "int32", "type": [ "integer", "null" ] }, "environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "error_type": { "type": "string" }, "events_in_range": { "description": "Count of error events within the requested time window.\nPresent only when `start_date` and `end_date` were supplied on the list request.", "format": "int64", "type": [ "integer", "null" ] }, "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" }, "environment_id": { "description": "Filter chart data to a specific environment.\nAlways AND-combined with project_id — an environment from a different project\nreturns zero-filled buckets rather than cross-project data.", "format": "int32", "type": [ "integer", "null" ] }, "start_time": { "format": "date-time", "type": "string" } }, "required": [ "start_time", "end_time" ], "type": "object" }, "EstimateBulkActivationRequest": { "description": "What to quote.\n\nExactly one of `all_eligible_projects` and a non-empty `project_ids` must be\ngiven. Defaulting an omitted scope to \"everything\" would make a typo cost\nmoney; defaulting it to \"nothing\" would make the endpoint silently useless.", "properties": { "all_eligible_projects": { "description": "Quote every project that still writes its spans to this instance.", "type": "boolean" }, "project_ids": { "description": "Quote exactly these projects. Projects that are already Cloud-primary\nare accepted here — re-shipping a window is the retry path — but are\nnever picked up by `all_eligible_projects`.", "items": { "format": "int32", "type": "integer" }, "type": [ "array", "null" ] }, "window_from": { "description": "Start of the window to ship. Defaults to the oldest span local retention\ncan still be holding.", "format": "date-time", "type": [ "string", "null" ] }, "window_to": { "description": "End of the window to ship. Defaults to now.", "format": "date-time", "type": [ "string", "null" ] } }, "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" ] }, "domain": { "description": "The tracked site's own domain, computed client-side by the SDK's\n`resolveDomain()` and sent as a sibling of `event_data` (not nested\ninside it). Used on the keyed ingest path (ADR-040 §3) to attribute\nself-referrals/channels correctly: there, `Host` names the Temps\nserver rather than the customer's site, so it can't be used for that.", "type": [ "string", "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" ] }, "session_id": { "description": "Client-generated session id fallback (see `visitor_id`).", "type": [ "string", "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" ] }, "visitor_id": { "description": "Client-generated visitor id, used only when the request carries no\nTemps-issued `_temps_visitor_id` cookie — i.e. Temps is used purely as\nan analytics backend for an app it doesn't deploy/proxy (gotempsh/temps#848).\nAccepts the SDK's `visitorId` key too, since the shared SDK helper that\ngenerates this value sends camelCase for every ingest endpoint.", "type": [ "string", "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": { "breakdown": { "oneOf": [ { "$ref": "#/components/schemas/EventBreakdown" }, { "type": "null" } ] }, "custom_events_only": { "type": [ "boolean", "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" }, "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" }, "EvictionFailedSandbox": { "description": "A sandbox an eviction could not destroy.", "properties": { "reason": { "type": "string" }, "sandbox_id": { "type": "string" } }, "required": [ "sandbox_id", "reason" ], "type": "object" }, "EvictionUnconfirmedContainer": { "description": "A sandbox destroyed without the node confirming its container is gone.", "properties": { "cleanup_command": { "description": "Run this on the node, if it comes back, to remove the sandbox's\nleftover containers. Nothing else will: the sandbox is destroyed, and\nits containers are not listed anywhere in Temps.", "type": "string" }, "reason": { "type": "string" }, "sandbox_id": { "type": "string" } }, "required": [ "sandbox_id", "reason", "cleanup_command" ], "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" }, "ExpirationRule": { "properties": { "field": { "$ref": "#/components/schemas/ResponseField" }, "warning_days": { "items": { "format": "int32", "minimum": 0, "type": "integer" }, "type": "array" } }, "required": [ "field", "warning_days" ], "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" }, "ExpiringArtifact": { "description": "One expiring item found in a value.", "properties": { "expires_at": { "format": "date-time", "type": "string" }, "kind": { "$ref": "#/components/schemas/ArtifactKind" }, "label": { "description": "Names the item for people, for example \"Certificate 'svc.example.test'\"\nor \"OpenPGP key 0x0123456789ABCDEF\". Never secret material and never\ntoken claims.", "type": "string" }, "not_before": { "format": "date-time", "type": [ "string", "null" ] } }, "required": [ "kind", "label", "expires_at" ], "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" }, "ExternalServiceBackupCapabilityResponse": { "properties": { "artifact": { "description": "Concrete artifact Cloud would mirror, such as `walg_repository`,\n`redis_walg_stream`, or `object_set`.", "type": "string" }, "cloud_backup_compatible": { "description": "Whether this running service can produce the physical WAL-G repository\nrequired by Temps Cloud. Logical dump fallback is intentionally not\nconsidered compatible.", "type": "boolean" }, "engine": { "type": "string" }, "reason": { "type": [ "string", "null" ] }, "recommended_image": { "type": [ "string", "null" ] }, "remediation": { "type": [ "string", "null" ] }, "verified": { "description": "False when Docker or the target container was unavailable, meaning the\nendpoint intentionally did not guess whether required tools exist.", "type": "boolean" }, "wal_g_installed": { "type": "boolean" } }, "required": [ "cloud_backup_compatible", "verified", "wal_g_installed", "engine", "artifact" ], "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" }, "service_name_snapshot": { "description": "Immutable provenance retained when the source service is deleted.", "type": [ "string", "null" ] }, "service_type_snapshot": { "type": [ "string", "null" ] }, "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" ] }, "continuous_archive_pinned_at": { "description": "When `continuous_archive_s3_source_id` was last set. Null alongside\na non-null source id means it was set by the original provisioning\nflow rather than an explicit repoint.", "type": [ "string", "null" ] }, "continuous_archive_s3_source_id": { "description": "S3 source ID that this service's continuous archiving (Postgres/\nTimescale WAL-G `archive_command`, or MariaDB's binlog shipper)\ncurrently writes to. Null for service types with no continuous\narchiving concept, or a Postgres/MariaDB service that has never had\none provisioned. Change it with `repoint_continuous_archive_source`.", "format": "int32", "type": [ "integer", "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" }, "FacetBackendKind": { "description": "Which storage engine a facet was created against. A deployment only ever\nruns one backend at a time (see `plugin.rs`'s storage selection), but\nstamping it on each row keeps the status fields unambiguous.", "enum": [ "clickhouse", "timescaledb" ], "type": "string" }, "FacetCapability": { "description": "Whether a facet registered now would actually cover anything\n(Feature Discoverability: \"not built\" and \"not set up\" need different UI).", "properties": { "configured": { "description": "False when the facet would populate for no project at all.", "type": "boolean" }, "reason": { "description": "Why, when `configured` is false. Always populated in that case.", "type": [ "string", "null" ] }, "setup_path": { "description": "Where the operator goes to change it.", "type": [ "string", "null" ] }, "uncovered_project_ids": { "description": "Projects whose spans this facet will **not** cover, because they are\nCloud-primary and store no spans on this instance. Non-empty alongside\n`configured: true` is a real and useful state: the facet works for the\nother projects, and the operator must be told which ones it misses\nrather than discovering it from an empty filter.", "items": { "format": "int32", "type": "integer" }, "type": "array" } }, "required": [ "configured", "uncovered_project_ids" ], "type": "object" }, "FacetField": { "description": "A dimension a caller can ask for distinct values of.\n\nRestricted to a closed enum on purpose: the field name reaches SQL as a\ncolumn identifier, so it can never be caller-supplied text.", "enum": [ "env", "service", "level", "stream", "project", "external_service", "node", "deploy", "container" ], "type": "string" }, "FacetInfo": { "description": "Public representation of a registered span attribute facet.", "properties": { "attribute_key": { "description": "The OTel attribute key, e.g. `enduser.id` or `galachain.contract`.", "type": "string" }, "backend": { "$ref": "#/components/schemas/FacetBackendKind" }, "created_at": { "example": "2025-10-12T12:15:47.609192Z", "type": "string" }, "error_message": { "description": "Populated when `status = failed`, explaining why.", "type": [ "string", "null" ] }, "rows_backfilled": { "description": "Rows backfilled so far. Only meaningful for the `timescaledb` backend\n— the `clickhouse` backend's mutation doesn't expose a row count\nuntil it's done, so this stays 0 there even while running.", "format": "int64", "type": "integer" }, "slot": { "description": "The slot column index 1..=20 (`facet_attr_N`).", "format": "int32", "minimum": 0, "type": "integer" }, "status": { "$ref": "#/components/schemas/FacetStatus" } }, "required": [ "attribute_key", "slot", "created_at", "status", "backend", "rows_backfilled" ], "type": "object" }, "FacetStatus": { "description": "Backfill/delete-clear lifecycle for a facet. See the module docs for how\nthe poller advances a facet through these states.", "enum": [ "pending", "running", "completed", "failed", "deleting" ], "type": "string" }, "FacetValue": { "description": "One distinct value of a facet field, with its occurrence count inside the\nqueried window.", "properties": { "count": { "format": "int64", "type": "integer" }, "value": { "type": "string" } }, "required": [ "value", "count" ], "type": "object" }, "FacetsAttrsResponse": { "properties": { "facets": { "type": "object" } }, "required": [ "facets" ], "type": "object" }, "FacetsResponse": { "description": "Response body for facet list.", "properties": { "data": { "items": { "$ref": "#/components/schemas/FacetInfo" }, "type": "array" } }, "required": [ "data" ], "type": "object" }, "FailureReportPreviewResponse": { "properties": { "error_message": { "type": [ "string", "null" ] }, "failed_job_type": { "type": "string" }, "github_issue_body": { "type": "string" }, "github_issue_title": { "type": "string" }, "redacted_log": { "description": "Redacted, editable draft of the failure trace. Shown in a textarea the\nuser can edit before sending — nothing is sent without their review.", "type": "string" }, "reporting_enabled": { "description": "Whether \"send to Temps\" should be offered. False when the operator\nopted out via `TEMPS_TELEMETRY`. The GitHub-issue path is unaffected.", "type": "boolean" } }, "required": [ "redacted_log", "reporting_enabled", "failed_job_type", "github_issue_title", "github_issue_body" ], "type": "object" }, "FailureSettingsSection": { "description": "Settings surface that fixes a given failure. The console maps each value to\na deep link; the API stays independent of console routes.", "enum": [ "source", "build", "deploy", "environment_variables", "git", "docker_registry", "build_limits" ], "type": "string" }, "FeatureMaturity": { "properties": { "docs_path": { "type": "string" }, "key": { "type": "string" }, "maturity": { "$ref": "#/components/schemas/Maturity" }, "reason": { "type": "string" } }, "required": [ "key", "maturity", "reason", "docs_path" ], "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" }, "FileDeletedResponse": { "description": "Reply of `DELETE /ai/v1/files/{file_id}`.", "properties": { "deleted": { "type": "boolean" }, "id": { "type": "string" }, "object": { "description": "Always `file`", "type": "string" } }, "required": [ "id", "object", "deleted" ], "type": "object" }, "FileObject": { "allOf": [ { "type": "object" }, { "properties": { "bytes": { "format": "int64", "type": "integer" }, "created_at": { "format": "int64", "type": "integer" }, "filename": { "type": "string" }, "id": { "type": "string" }, "object": { "description": "Always `file`", "type": "string" }, "purpose": { "description": "`batch` for uploads, `batch_output` for batch results", "type": "string" } }, "required": [ "id", "object" ], "type": "object" } ], "description": "A file object as returned by the provider." }, "Finding": { "properties": { "code": { "type": "string" }, "message": { "type": "string" }, "status": { "$ref": "#/components/schemas/CheckStatus" } }, "required": [ "code", "status", "message" ], "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 ingress relay's :8080 is published on.", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "image": { "description": "Image reference the container was created with (e.g. an immutable\n`ghcr.io/gotempsh/temps-preview-gateway@sha256:…` reference).", "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": "Trusted control network the gateway starts on. It is additionally attached\nto each per-sandbox isolated network during reconciliation.", "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" }, "GeoDatabaseStatusResponse": { "description": "Freshness of the geolocation database backing this instance", "properties": { "age_days": { "description": "Age in days of the loaded data, from `build_time` when known and from\n`last_refreshed_at` otherwise", "example": 3, "format": "int64", "type": [ "integer", "null" ] }, "build_epoch": { "description": "MaxMind `build_epoch` of the loaded database (Unix seconds)", "example": 1767225600, "format": "int64", "type": [ "integer", "null" ] }, "build_time": { "description": "When MaxMind built the loaded data (ISO 8601, UTC)", "example": "2026-09-01T02:00:00Z", "type": [ "string", "null" ] }, "is_stale": { "description": "Whether `age_days` has passed `stale_after_days`, or the last check\nfailed", "example": false, "type": "boolean" }, "last_check_at": { "description": "When a refresh was last attempted, successful or not (ISO 8601, UTC)", "example": "2026-09-17T03:14:00Z", "type": [ "string", "null" ] }, "last_check_status": { "description": "`ok` or `error` for the most recent refresh attempt; `null` when none\nhas run yet", "example": "ok", "type": [ "string", "null" ] }, "last_error": { "description": "Redacted reason the last refresh failed, so an operator can act on it\nwithout reading server logs", "example": "Geo database download from source 'maxmind_official' failed: HTTP 401", "type": [ "string", "null" ] }, "last_refreshed_at": { "description": "When new database bytes were last installed (ISO 8601, UTC)", "example": "2026-09-01T03:14:00Z", "type": [ "string", "null" ] }, "license_key_configured": { "description": "Whether a MaxMind license key is configured. The key itself is never\nreturned, logged, or persisted.", "example": true, "type": "boolean" }, "refresh_interval_hours": { "description": "How often the scheduled refresh job runs", "example": 24, "format": "int64", "minimum": 0, "type": "integer" }, "source": { "description": "Where the loaded database was downloaded from: `maxmind_official` when\na license key is configured, `bundled_github` otherwise. `null` when no\nrefresh has run yet (the database was provisioned by the operator).", "example": "maxmind_official", "type": [ "string", "null" ] }, "stale_after_days": { "description": "Age after which this instance treats the database, and cached IP\nlookups, as stale", "example": 30, "format": "int64", "type": "integer" } }, "required": [ "license_key_configured", "stale_after_days", "is_stale", "refresh_interval_hours" ], "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" }, "GeoSettings": { "description": "Geolocation database configuration and freshness state.\n\nBoth the data-policy knobs an admin sets and the metadata the refresh job\nrecords live on one typed struct on purpose. The `settings` row is a shared\nJSON document and `AppSettings` is deserialized/reserialized in full by the\ngeneric settings endpoint, so any geo key kept *outside* this struct would\nbe silently dropped the next time an unrelated settings page was saved.\n\nThe license key is stored as ciphertext only\n([`GeoSettings::maxmind_license_key_encrypted`]). The plaintext field\nbeside it is write-only input from the admin UI: it is `skip_serializing`,\nso it can never be persisted or returned, and\n[`GeoSettings::apply_license_key_update`] clears it after encrypting.", "properties": { "build_epoch": { "default": null, "description": "MaxMind `build_epoch` of the database that was last installed.", "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "last_check_at": { "default": null, "description": "When a refresh was last attempted, successful or not.", "format": "date-time", "type": [ "string", "null" ] }, "last_check_status": { "default": null, "description": "[`GEO_CHECK_STATUS_OK`] or [`GEO_CHECK_STATUS_ERROR`].", "type": [ "string", "null" ] }, "last_error": { "default": null, "description": "Redacted reason the last refresh failed, so an operator can act on it\nwithout reading server logs. Never contains the license key.", "type": [ "string", "null" ] }, "last_refreshed_at": { "default": null, "description": "When new database bytes were last installed and swapped in.\nSelf-recorded by the refresh job; never writable by a client.", "format": "date-time", "type": [ "string", "null" ] }, "maxmind_license_key_encrypted": { "default": null, "description": "AES-256-GCM ciphertext of the MaxMind license key, as produced by\n`EncryptionService::encrypt_string`. Never returned by the API.", "type": [ "string", "null" ] }, "refresh_interval_hours": { "default": null, "description": "How often the scheduled refresh job runs. `None` means\n[`DEFAULT_GEO_REFRESH_INTERVAL_HOURS`]; read it through\n[`GeoSettings::effective_refresh_interval_hours`].", "example": 24, "format": "int32", "maximum": 8760, "minimum": 1, "type": [ "integer", "null" ] }, "source": { "default": null, "description": "[`GEO_SOURCE_MAXMIND_OFFICIAL`] or [`GEO_SOURCE_BUNDLED_GITHUB`].", "type": [ "string", "null" ] }, "stale_lookup_days": { "default": null, "description": "Age at which a stored IP -> location row is re-resolved on its next\nlookup. `None` means [`DEFAULT_GEO_STALE_LOOKUP_DAYS`]; read it through\n[`GeoSettings::effective_stale_lookup_days`].", "example": 30, "format": "int32", "maximum": 3650, "minimum": 1, "type": [ "integer", "null" ] } }, "type": "object" }, "GeoSettingsMasked": { "description": "Geolocation settings with the MaxMind license key masked.\n\nThe stored value is AES-256-GCM ciphertext, and neither it nor the\nplaintext is ever returned: the UI only needs to know whether a key is\nsaved, so it can render the \"leave blank to keep current\" affordance the\nemail-provider credentials use. The refresh metadata below is reported\nread-only — it is written by the refresh job, not by a settings save.", "properties": { "effective_refresh_interval_hours": { "description": "Refresh cadence actually applied, with defaults and bounds resolved.", "format": "int32", "minimum": 0, "type": "integer" }, "effective_stale_lookup_days": { "description": "Staleness window actually applied, with defaults and bounds resolved.", "format": "int32", "minimum": 0, "type": "integer" }, "last_check_at": { "description": "When a refresh was last attempted, successful or not (ISO 8601, UTC).", "type": [ "string", "null" ] }, "last_check_status": { "description": "`ok` or `error` for the most recent refresh attempt.", "type": [ "string", "null" ] }, "last_error": { "description": "Redacted reason the last refresh failed. Never contains the key.", "type": [ "string", "null" ] }, "last_refreshed_at": { "description": "When new database bytes were last installed (ISO 8601, UTC).", "type": [ "string", "null" ] }, "maxmind_license_key_saved": { "description": "True when a MaxMind license key is stored. The key is never returned.", "type": "boolean" }, "refresh_interval_hours": { "description": "`null` means the effective default (24 hours).", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "source": { "description": "`maxmind_official` or `bundled_github`.", "type": [ "string", "null" ] }, "stale_lookup_days": { "description": "`null` means the effective default (30 days).", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] } }, "required": [ "effective_refresh_interval_hours", "effective_stale_lookup_days", "maxmind_license_key_saved" ], "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 read when it is not marked secret. Required\nby the dashboard so duplicate keys cannot select a different row.", "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" }, "GitBindingResponse": { "properties": { "connectionId": { "format": "int32", "type": "integer" }, "createdAt": { "type": "string" }, "id": { "format": "int64", "type": "integer" }, "projectId": { "format": "int32", "type": "integer" }, "remoteName": { "type": "string" }, "repositoryId": { "format": "int32", "type": "integer" }, "repositoryUrl": { "type": "string" }, "status": { "description": "`configured` means the durable authorization exists; it does not claim a live remote.", "type": "string" }, "updatedAt": { "type": "string" } }, "required": [ "id", "projectId", "connectionId", "repositoryId", "repositoryUrl", "remoteName", "status", "createdAt", "updatedAt" ], "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" }, "GitRef": { "description": "Git repository reference (supports any git provider: GitHub, GitLab, Bitbucket, etc.)", "properties": { "path": { "description": "Path within the repository (for monorepos)\nAlso accepts \"subfolder\" as an alias in YAML/JSON", "type": [ "string", "null" ] }, "ref": { "description": "Git reference (branch, tag, or commit)", "type": "string" }, "url": { "description": "Git repository URL (e.g., \"https://github.com/owner/repo.git\" or \"https://gitlab.com/owner/repo.git\")", "type": "string" } }, "required": [ "url" ], "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" }, "GlobalAnalyticsResponse": { "properties": { "rows": { "items": { "$ref": "#/components/schemas/GlobalAnalyticsRow" }, "type": "array" }, "total": { "format": "int64", "type": "integer" }, "total_views": { "format": "int64", "type": "integer" } }, "required": [ "rows", "total", "total_views" ], "type": "object" }, "GlobalAnalyticsRow": { "properties": { "avg_time_seconds": { "format": "double", "type": [ "number", "null" ] }, "bounce_rate": { "format": "double", "type": [ "number", "null" ] }, "cls_p75": { "format": "double", "type": [ "number", "null" ] }, "fcp_p75": { "format": "double", "type": [ "number", "null" ] }, "inp_p75": { "format": "double", "type": [ "number", "null" ] }, "key": { "type": "string" }, "lcp_p75": { "format": "double", "type": [ "number", "null" ] }, "project_id": { "format": "int32", "type": "integer" }, "project_name": { "type": "string" }, "sessions": { "format": "int64", "type": "integer" }, "ttfb_p75": { "format": "double", "type": [ "number", "null" ] }, "views": { "format": "int64", "type": "integer" }, "visitors": { "format": "int64", "type": "integer" } }, "required": [ "key", "project_id", "project_name", "views", "sessions", "visitors" ], "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": { "ai_model": { "type": "string" }, "ai_permission_mode": { "type": "string" }, "ai_provider": { "type": "string" }, "ai_thinking_level": { "type": [ "string", "null" ] }, "context_id": { "type": "string" }, "context_type": { "type": "string" }, "context_usage": { "oneOf": [ { "$ref": "#/components/schemas/ContextWindowUsageResponse" }, { "type": "null" } ] }, "created_at": { "type": "string" }, "failure": { "oneOf": [ { "$ref": "#/components/schemas/ChatFailureResponse" }, { "type": "null" } ] }, "last_activity_at": { "type": "string" }, "project_id": { "format": "int32", "type": [ "integer", "null" ] }, "project_name": { "type": [ "string", "null" ] }, "project_slug": { "type": [ "string", "null" ] }, "public_id": { "type": "string" }, "status": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "turn_status": { "description": "Server-authoritative lifecycle for the current/most recent turn.", "type": "string" } }, "required": [ "public_id", "context_type", "context_id", "status", "created_at", "last_activity_at", "ai_provider", "ai_model", "ai_permission_mode", "turn_status" ], "type": "object" }, "GlobalErrorGroupResponse": { "properties": { "affected_users": { "format": "int64", "type": "integer" }, "assigned_to": { "type": [ "string", "null" ] }, "environment_name": { "type": [ "string", "null" ] }, "error_type": { "type": "string" }, "events_in_range": { "format": "int64", "type": "integer" }, "first_seen": { "type": "string" }, "id": { "format": "int32", "type": "integer" }, "last_seen": { "type": "string" }, "project_id": { "format": "int32", "type": "integer" }, "project_name": { "type": "string" }, "project_slug": { "type": "string" }, "status": { "type": "string" }, "title": { "type": "string" }, "total_count": { "format": "int64", "type": "integer" } }, "required": [ "id", "title", "error_type", "status", "project_id", "project_name", "project_slug", "first_seen", "last_seen", "total_count", "events_in_range", "affected_users" ], "type": "object" }, "GlobalErrorGroupsQuery": { "properties": { "end_date": { "format": "date-time", "type": [ "string", "null" ] }, "page": { "format": "int64", "minimum": 0, "type": "integer" }, "page_size": { "format": "int64", "minimum": 0, "type": "integer" }, "project_id": { "format": "int32", "type": [ "integer", "null" ] }, "search": { "type": [ "string", "null" ] }, "start_date": { "format": "date-time", "type": [ "string", "null" ] }, "status": { "type": [ "string", "null" ] } }, "type": "object" }, "GlobalErrorGroupsResponse": { "properties": { "data": { "items": { "$ref": "#/components/schemas/GlobalErrorGroupResponse" }, "type": "array" }, "pagination": { "$ref": "#/components/schemas/PaginationMeta" } }, "required": [ "data", "pagination" ], "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" }, "GlobalLogCapabilities": { "description": "What the log explorer can offer on this instance. Attribute facets,\nhistograms and `GROUP BY` analytics need the ClickHouse line index; when\nit is missing the client shows *why* and where to configure it instead\nof hiding the feature (CLAUDE.md: unconfigured features onboard).", "properties": { "analytics": { "$ref": "#/components/schemas/AnalyticsCapability" }, "collection": { "$ref": "#/components/schemas/LogCollectionCapability" } }, "required": [ "analytics", "collection" ], "type": "object" }, "GlobalLogFacetsRequest": { "allOf": [ { "$ref": "#/components/schemas/GlobalLogSearchRequest" }, { "properties": { "fields": { "description": "Fields to return distinct values for. Empty returns the default set.", "items": { "$ref": "#/components/schemas/FacetField" }, "type": "array" } }, "type": "object" } ], "description": "Facet request: the same filter body plus the fields to aggregate." }, "GlobalLogFacetsResponse": { "description": "Distinct values and counts per requested field, inside the current window.", "properties": { "external_service_names": { "additionalProperties": { "type": "string" }, "description": "Display names for the returned `external_service_id` values; see\n`project_names`.", "propertyNames": { "type": "string" }, "type": "object" }, "facets": { "description": "Keyed by field name (`env`, `service`, `level`, `node_id`, …). Values\nare ordered by count, descending.", "type": "object" }, "partial": { "description": "`true` when a field's value list was capped or timed out, so it is a\nprefix rather than the complete set. Reported rather than glossed: the\npoint of a facet is that a user can trust it to surface values they\nhave never seen on screen.", "type": "boolean" }, "project_names": { "additionalProperties": { "type": "string" }, "description": "Display names for the returned `project_id` values, keyed by value.\nResolved here, under the log access that produced the facets, so a\ncaller who may read these logs can tell the projects apart without\nalso needing permission to read projects — the same names search\nlines carry as `owner`. A returned value missing from this map names a\nproject this instance no longer has.", "propertyNames": { "type": "string" }, "type": "object" } }, "required": [ "facets", "partial", "project_names", "external_service_names" ], "type": "object" }, "GlobalLogLine": { "allOf": [ { "$ref": "#/components/schemas/LogSearchLine" }, { "properties": { "env": { "type": "string" }, "external_service_id": { "format": "int32", "type": [ "integer", "null" ] }, "owner": { "description": "Display name of the owning project or external service.", "type": "string" }, "project_id": { "description": "`None` for external-service lines.", "format": "int32", "type": [ "integer", "null" ] } }, "required": [ "owner", "env" ], "type": "object" } ], "description": "One line in a global search result." }, "GlobalLogSearchRequest": { "description": "Filter body shared by `/logs/global/search` and `/logs/global/facets`.\n\nBoth endpoints take the identical filter set so a facet count always\ndescribes the search the user is actually looking at.", "properties": { "attrs": { "description": "Attribute predicates (ADR-047 §5): `` with `op` one of\n`=`, `!=`, `^=` (prefix), `>`, `<`, or `?` for \"exists\". Requires\nthe line index; when combined with `text`, the text filter is applied\nin memory over the lines the index already matched (the index holds\nno message bytes, so it cannot answer `text` on its own).", "items": { "type": "string" }, "type": "array" }, "container_ids": { "description": "Docker container IDs.", "items": { "type": "string" }, "type": "array" }, "cursor": { "description": "Opaque cursor from the previous page's `next_cursor`.", "type": [ "string", "null" ] }, "deploy_id": { "format": "int32", "type": [ "integer", "null" ] }, "end_time": { "type": "string" }, "envs": { "items": { "type": "string" }, "type": "array" }, "external_services": { "description": "Database/service IDs or names, not container service labels.", "items": { "type": "string" }, "type": "array" }, "levels": { "items": { "$ref": "#/components/schemas/LogLevel" }, "type": "array" }, "node_ids": { "items": { "format": "int32", "type": "integer" }, "type": "array" }, "page_size": { "description": "Defaults to 200, server-capped at 1000.", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "projects": { "description": "Match project ID, slug or name. Empty selects all authorized projects.", "items": { "type": "string" }, "type": "array" }, "scopes": { "description": "Explicit resource identities, e.g. `application:12` or `service:34`.", "items": { "type": "string" }, "type": "array" }, "services": { "description": "Container service labels (the `service` column), e.g. `web`, `worker`.", "items": { "type": "string" }, "type": "array" }, "source": { "$ref": "#/components/schemas/LogSourceKind" }, "start_time": { "type": "string" }, "text": { "description": "Case-insensitive substring match over the message.", "type": [ "string", "null" ] } }, "required": [ "start_time", "end_time" ], "type": "object" }, "GlobalLogSearchResponse": { "description": "A page of global search results.", "properties": { "lines": { "description": "Newest first, ordered by `(timestamp, container_id, line_id)`.", "items": { "$ref": "#/components/schemas/GlobalLogLine" }, "type": "array" }, "next_cursor": { "description": "Opaque cursor for the next (older) page, or `None` on the last page.\n\nThis is a keyset position over the store's own sort order, so page 40\ncosts what page 1 costs. Stays populated on a partial page too — that\nis the whole point: the user can press Next to keep searching.", "type": [ "string", "null" ] }, "partial": { "description": "`true` when the store's time/byte budget ran out before this page\ncould be proven complete (`scanned_back_to` explains how far).", "type": "boolean" }, "scanned_back_to": { "description": "Set when `partial` is `true`: every chunk ending after this timestamp\nhas been searched, nothing older has yet.", "type": [ "string", "null" ] } }, "required": [ "lines", "partial" ], "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" }, "GlobalTraceSummariesResponse": { "properties": { "data": { "items": { "$ref": "#/components/schemas/GlobalTraceSummary" }, "type": "array" }, "projects": { "items": { "$ref": "#/components/schemas/TraceProject" }, "type": "array" }, "total": { "format": "int64", "minimum": 0, "type": "integer" }, "windows": { "description": "Effective per-project windows; totals and rows describe these windows.", "items": { "$ref": "#/components/schemas/GlobalTraceWindow" }, "type": "array" } }, "required": [ "data", "total", "projects", "windows" ], "type": "object" }, "GlobalTraceSummary": { "allOf": [ { "$ref": "#/components/schemas/TraceSummary" }, { "properties": { "project_id": { "format": "int32", "type": "integer" }, "project_name": { "type": "string" }, "project_slug": { "type": "string" } }, "required": [ "project_id", "project_name", "project_slug" ], "type": "object" } ] }, "GlobalTraceWindow": { "description": "A global query can use different stores and effective windows per project.\nA non-null clamp explicitly tells clients the pre-cutover range is excluded;\nrequest an earlier window to read the older source (ADR-040/041).", "properties": { "effective_end_time": { "format": "date-time", "type": "string" }, "effective_start_time": { "format": "date-time", "type": "string" }, "project_id": { "format": "int32", "type": "integer" }, "source": { "$ref": "#/components/schemas/CloudTelemetryWriteMode" }, "window_clamped_at": { "format": "date-time", "type": [ "string", "null" ] } }, "required": [ "project_id", "source", "effective_start_time", "effective_end_time" ], "type": "object" }, "GlobalTracesResponse": { "properties": { "data": { "items": { "$ref": "#/components/schemas/SpanRecord" }, "type": "array" }, "total": { "format": "int64", "minimum": 0, "type": "integer" }, "windows": { "description": "Effective per-project windows; totals and rows describe these windows.", "items": { "$ref": "#/components/schemas/GlobalTraceWindow" }, "type": "array" } }, "required": [ "data", "total", "windows" ], "type": "object" }, "GroupKey": { "description": "What to group or facet by.", "oneOf": [ { "description": "A stream label (`service`, `env`, `level`, …).", "properties": { "kind": { "enum": [ "label" ], "type": "string" }, "name": { "$ref": "#/components/schemas/FacetField", "description": "A stream label (`service`, `env`, `level`, …)." } }, "required": [ "name", "kind" ], "type": "object" }, { "description": "An attribute key.", "properties": { "kind": { "enum": [ "attr" ], "type": "string" }, "name": { "description": "An attribute key.", "type": "string" } }, "required": [ "name", "kind" ], "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" }, "HarnessCheck": { "properties": { "action": { "type": [ "string", "null" ] }, "detail": { "type": "string" }, "duration_ms": { "format": "int64", "minimum": 0, "type": "integer" }, "id": { "type": "string" }, "label": { "type": "string" }, "status": { "$ref": "#/components/schemas/HarnessCheckStatus" } }, "required": [ "id", "label", "status", "detail", "duration_ms" ], "type": "object" }, "HarnessCheckMode": { "enum": [ "preflight", "smoke" ], "type": "string" }, "HarnessCheckOverall": { "enum": [ "passed", "warning", "failed" ], "type": "string" }, "HarnessCheckReport": { "properties": { "checked_at": { "type": "string" }, "checks": { "items": { "$ref": "#/components/schemas/HarnessCheck" }, "type": "array" }, "diagnostic_id": { "type": "string" }, "mode": { "$ref": "#/components/schemas/HarnessCheckMode" }, "overall": { "$ref": "#/components/schemas/HarnessCheckOverall" }, "provider_id": { "type": "string" } }, "required": [ "provider_id", "mode", "overall", "checked_at", "diagnostic_id", "checks" ], "type": "object" }, "HarnessCheckStatus": { "enum": [ "passed", "warning", "failed", "not_tested" ], "type": "string" }, "HarnessSmokeRequest": { "properties": { "consent": { "description": "Explicit acknowledgement that this check makes a billable model request.", "type": "boolean" }, "model": { "description": "Optional catalog model identifier. It is validated by the provider adapter.", "type": [ "string", "null" ] } }, "required": [ "consent" ], "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" }, "HasTracesResponse": { "properties": { "has_traces": { "type": "boolean" } }, "required": [ "has_traces" ], "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" ] }, "dns_resolver": { "oneOf": [ { "$ref": "#/components/schemas/DnsResolverHeartbeat", "description": "Per-node DNS resolver health (ADR-024), reported by agents new enough\nto have it. `None` means either an older agent binary, or a\nheartbeat that raced before the agent's network-sync loop first\nran — a true single-host node with no `compute_cidr` allocation\nnever touches cluster DNS and always reports `None` here, which is\nexpected, not stale data. The stored columns are left untouched when\n`None`, same treatment as `architecture` above." }, { "type": "null" } ] }, "docker_socket_projects": { "description": "Project slugs this node grants host Docker access to (ADR 045), read\nby the agent from its own `TEMPS_DOCKER_SOCKET_PROJECTS`.\n\nAdvisory only: it tells the scheduler where a granted project *may* be\nplaced. It can never cause a socket to be mounted — that decision is\nmade by the executing process against its own environment. `None` from\na pre-ADR-045 agent leaves the stored value untouched; an empty array\nclears it.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "labels": { "description": "Updated node labels for scheduling (allows runtime label changes)." }, "public_ingress": { "oneOf": [ { "$ref": "#/components/schemas/PublicIngressHeartbeat" }, { "type": "null" } ] } }, "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" }, "HistogramBucket": { "description": "One time bucket of a histogram, optionally split by a group value.", "properties": { "count": { "format": "int64", "type": "integer" }, "group": { "type": [ "string", "null" ] }, "ts": { "type": "string" } }, "required": [ "ts", "count" ], "type": "object" }, "HistogramResponse": { "properties": { "buckets": { "items": { "$ref": "#/components/schemas/HistogramBucket" }, "type": "array" } }, "required": [ "buckets" ], "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": { "conflicts": { "description": "Generated hostnames whose records the sync may not write until the\napply adopts or skips each one. Only a preview reports them: an apply\nwith any left unresolved changes nothing and fails.", "items": { "$ref": "#/components/schemas/DnsRecordConflict" }, "type": "array" }, "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", "conflicts", "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" }, "HttpCheckList": { "properties": { "items": { "items": { "$ref": "#/components/schemas/HttpCheckView" }, "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" }, "HttpCheckMethod": { "enum": [ "get", "head" ], "type": "string" }, "HttpCheckSpec": { "description": "This is a declarative HTTP recipe, never executable code.\nHeaders may contain secrets: hosts must encrypt this specification at rest.", "properties": { "accepted_statuses": { "items": { "format": "int32", "minimum": 0, "type": "integer" }, "type": "array" }, "credential_header": { "description": "Credential injection is separate from detection and always explicitly selected.", "type": [ "string", "null" ] }, "credential_prefix": { "type": "string" }, "expiration": { "oneOf": [ { "$ref": "#/components/schemas/ExpirationRule" }, { "type": "null" } ] }, "headers": { "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" }, "type": "object" }, "method": { "$ref": "#/components/schemas/HttpCheckMethod" }, "numeric_rules": { "items": { "$ref": "#/components/schemas/NumericRule" }, "type": "array" }, "url": { "type": "string" } }, "required": [ "url", "method", "accepted_statuses" ], "type": "object" }, "HttpCheckView": { "properties": { "automatic_provider": { "type": [ "string", "null" ] }, "enabled": { "type": "boolean" }, "env_var_id": { "format": "int32", "type": [ "integer", "null" ] }, "id": { "format": "int32", "type": "integer" }, "interval_seconds": { "format": "int32", "type": "integer" }, "kind": { "$ref": "#/components/schemas/CheckKind" }, "last_checked_at": { "format": "date-time", "type": [ "string", "null" ] }, "name": { "type": "string" }, "next_check_at": { "format": "date-time", "type": "string" }, "project_id": { "format": "int32", "type": "integer" }, "result": { "oneOf": [ { "$ref": "#/components/schemas/VerificationResult" }, { "type": "null" } ] }, "secret_id": { "format": "int32", "type": [ "integer", "null" ] } }, "required": [ "id", "project_id", "kind", "name", "enabled", "interval_seconds", "next_check_at" ], "type": "object" }, "HttpChecksCapabilities": { "properties": { "alerts_configured": { "type": "boolean" }, "alerts_setup_path": { "type": "string" }, "detection_rule_count": { "minimum": 0, "type": "integer" } }, "required": [ "detection_rule_count", "alerts_configured", "alerts_setup_path" ], "type": "object" }, "ImageRetentionSettings": { "description": "System-wide retention policy for locally-built deployment images.\n\nThe nightly cleanup removes a Temps-built image only once *every*\ndeployment that references it is older than the owning project's retention\nwindow. Deleting an image makes rollback/promotion to that deployment\nimpossible, so the default is deliberately generous: it is a rollback\nwindow, not a cache TTL.", "properties": { "default_hours": { "default": 336, "description": "Default hours to keep a built deployment image when the owning project\nhas no `image_retention_hours` override. Valid range 1..=8760.", "example": 336, "format": "int64", "maximum": 8760, "minimum": 1, "type": "integer" }, "enabled": { "default": true, "description": "Whether the nightly pass removes expired deployment images at all.\nDisabling it keeps every built image forever (the pre-0.1 behaviour).", "type": "boolean" } }, "type": "object" }, "ImageRuntimeConfig": { "description": "Editable runtime settings for a single-container image template.\n\nMulti-container service templates will use a separate container collection;\nkeeping this shape explicitly singular prevents silently applying one image\nor command to an unrelated sidecar.", "properties": { "command": { "description": "`None` explicitly means \"use the image's default command\". Keep the\nserialized `null` when a runtime snapshot exists so clients can\ndistinguish that choice from an omitted runtime setting.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "healthCheckPath": { "type": [ "string", "null" ] }, "imageRef": { "type": "string" } }, "required": [ "imageRef" ], "type": "object" }, "ImportApplicationWorkspaceGitRequest": { "additionalProperties": false, "properties": { "depth": { "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "git_connection_id": { "description": "Opaque user-owned connection reference. The credential value remains\nserver-side and is restricted to the provider's configured origin.", "format": "int32", "type": [ "integer", "null" ] }, "revision": { "type": [ "string", "null" ] }, "url": { "type": "string" } }, "required": [ "url" ], "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" }, "ImportEmailDomainRequest": { "description": "Request body for importing an already-provisioned email domain.\n\nUse this when the domain identity was created directly in the email\nprovider's own console or API — Temps will look it up rather than\nattempting to re-create it, avoiding duplicate or conflicting identities.\n\n`provider_identity_id` is required for Scaleway (where the provider keys\nlookups off an internal UUID rather than the domain name) and optional for\nSES (which uses the domain name for all lookups). If a required field is\nmissing, the provider will surface a clear error.", "properties": { "domain": { "description": "Domain name (e.g., \"updates.example.com\")", "example": "updates.example.com", "type": "string" }, "provider_id": { "description": "Provider ID to import the domain into", "format": "int32", "type": "integer" }, "provider_identity_id": { "description": "Provider-internal identity identifier. Required for Scaleway (the domain\nUUID shown in the Scaleway console); ignored/optional for SES.", "example": "12345678-1234-1234-1234-123456789012", "type": [ "string", "null" ] } }, "required": [ "provider_id", "domain" ], "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" }, "ImportLocalCredentialResponse": { "properties": { "auth_type": { "type": "string" }, "credential_verification_status": { "type": "string" }, "provider": { "$ref": "#/components/schemas/ProviderCatalogDto" }, "provider_id": { "type": "string" }, "saved": { "type": "boolean" }, "source": { "type": "string" }, "verification_hint": { "type": [ "string", "null" ] }, "workspace_ready": { "type": "boolean" } }, "required": [ "saved", "credential_verification_status", "provider_id", "auth_type", "source", "workspace_ready", "provider" ], "type": "object" }, "ImportManagedRecordRequest": { "description": "Request to import (adopt) an existing record into temps management", "properties": { "domain": { "description": "Domain (any FQDN under a managed zone)", "example": "example.com", "type": "string" }, "environment_id": { "description": "Environment this record belongs to (stamped into the ownership marker)", "format": "int32", "type": [ "integer", "null" ] }, "name": { "description": "Record name relative to the zone (\"@\" for apex)", "example": "app", "type": "string" }, "project_id": { "description": "Project this record belongs to (stamped into the ownership marker)", "format": "int32", "type": [ "integer", "null" ] }, "record_type": { "$ref": "#/components/schemas/DnsRecordType", "description": "Record type" } }, "required": [ "domain", "name", "record_type" ], "type": "object" }, "ImportManagedRecordResponse": { "description": "Result of importing a record into temps management", "properties": { "environment_id": { "description": "Environment stamped in the ownership marker", "format": "int32", "type": [ "integer", "null" ] }, "name": { "description": "Record name that was imported", "type": "string" }, "project_id": { "description": "Project stamped in the ownership marker", "format": "int32", "type": [ "integer", "null" ] }, "record_type": { "description": "Record type that was imported", "type": "string" } }, "required": [ "name", "record_type" ], "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": [ { "$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." }, { "type": "null" } ] }, "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": [ { "$ref": "#/components/schemas/ImportPlan", "description": "Import plan" }, { "type": "null" } ] }, "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": [ { "$ref": "#/components/schemas/ValidationReport", "description": "Validation report" }, { "type": "null" } ] }, "warnings": { "description": "Warnings (if any)", "items": { "type": "string" }, "type": "array" } }, "required": [ "session_id", "status", "errors", "warnings", "created_at", "updated_at" ], "type": "object" }, "ImportTraefikAcmeJsonRequest": { "description": "Request body for Path B: import from Traefik's `acme.json`.\n\n`Debug` is hand-written: `acme_json` contains Traefik's private keys and\nmust never appear in logs. Only the host list, renewal method, dry-run flag,\nand byte length are logged.", "properties": { "acknowledge_manual_dns_renewal": { "description": "Required when `renewal_method` is `\"dns-01\"` and no auto-manage zone\ncovers the host.", "type": "boolean" }, "acme_json": { "description": "Raw contents of the Traefik `acme.json` file (uploaded by the CLI or\npasted in the console). **Never** a server-side file path.\nRedacted in `Debug` output — the field holds private key material.", "type": "string" }, "dry_run": { "description": "`true` → full parse and validation, no writes. The identical per-host\nverdicts are returned, giving the operator a preview before committing.", "type": "boolean" }, "hosts": { "description": "Hosts to import. Only hosts that appear in the document's certificates\n(by X.509 SAN, not JSON `domain.main`) are accepted.", "items": { "type": "string" }, "type": "array" }, "renewal_method": { "description": "`\"http-01\"` or `\"dns-01\"`. Stored as `verification_method` so the\nrenewal scheduler knows how to renew.", "type": "string" } }, "required": [ "acme_json", "hosts", "renewal_method" ], "type": "object" }, "ImportTraefikAcmeJsonResponse": { "description": "Response body for the Path B import endpoint.", "properties": { "dry_run": { "type": "boolean" }, "failed": { "minimum": 0, "type": "integer" }, "succeeded": { "minimum": 0, "type": "integer" }, "total_requested": { "minimum": 0, "type": "integer" }, "verdicts": { "items": { "$ref": "#/components/schemas/ImportedHostVerdict" }, "type": "array" } }, "required": [ "dry_run", "total_requested", "succeeded", "failed", "verdicts" ], "type": "object" }, "ImportedHostVerdict": { "description": "Per-host result from a Path B import.", "properties": { "error": { "description": "Human-readable failure reason when `success` is `false`.", "type": [ "string", "null" ] }, "host": { "type": "string" }, "not_after": { "description": "ISO 8601 expiry of the imported certificate.", "type": [ "string", "null" ] }, "sans": { "description": "DNS SANs carried in the imported certificate.", "items": { "type": "string" }, "type": "array" }, "success": { "description": "Whether the cert was written (or would be written on `dry_run: false`).", "type": "boolean" } }, "required": [ "host", "success", "sans" ], "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" }, "IngestErrorSummary": { "description": "One aggregated ingest-failure group: \"this signal failed this way N times\".\n\nThe pipeline-stats counters say *how many* records were dropped;\nthis says *why*. Rows are grouped by `(signal_type, error_class)` rather\nthan stored per-event, so a sustained outage collapses into one row with a\nrising `count` instead of flooding the table.\n\n`sample_message` is one representative backend error string, kept for the\ndetail a class name cannot carry (the failing column, the refused address).\nIt is a sample, not a guarantee: which occurrence it came from is\nunspecified.", "properties": { "count": { "description": "How many times this `(signal_type, error_class)` pair has failed.", "format": "int64", "minimum": 0, "type": "integer" }, "error_class": { "description": "Stable, low-cardinality failure class — see `OtelError::error_class`.", "type": "string" }, "first_seen": { "format": "date-time", "type": "string" }, "last_seen": { "format": "date-time", "type": "string" }, "sample_message": { "description": "A representative backend error message for this group.", "type": "string" }, "signal_type": { "description": "Which signal was being written: `metrics`, `spans`, or `logs`.", "type": "string" } }, "required": [ "signal_type", "error_class", "sample_message", "count", "first_seen", "last_seen" ], "type": "object" }, "IngestErrorsResponse": { "properties": { "errors": { "description": "Failure groups, most recently seen first.", "items": { "$ref": "#/components/schemas/IngestErrorSummary" }, "type": "array" } }, "required": [ "errors" ], "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" }, "InstallPluginRequest": { "additionalProperties": false, "properties": { "grants": { "oneOf": [ { "$ref": "#/components/schemas/PluginGrantConfig" }, { "type": "null" } ] }, "name": { "description": "Validated registry name only. URLs, paths, versions, and hashes are not\naccepted from HTTP callers.", "type": "string" } }, "required": [ "name" ], "type": "object" }, "InstallPluginResponse": { "properties": { "message": { "type": "string" }, "name": { "type": "string" }, "platform": { "type": "string" }, "sha256": { "type": "string" }, "version": { "type": "string" } }, "required": [ "name", "version", "platform", "sha256", "message" ], "type": "object" }, "IntegrationResponse": { "properties": { "config": { "oneOf": [ { "$ref": "#/components/schemas/ProviderConfig", "description": "Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)." }, { "type": "null" } ] }, "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" }, "LatestDeploymentMediaResponse": { "properties": { "projects": { "additionalProperties": { "$ref": "#/components/schemas/LatestDeploymentMediaResponseItem" }, "description": "Latest deployment media keyed by project ID. Projects with no\ndeployments are omitted.", "propertyNames": { "type": "string" }, "type": "object" } }, "required": [ "projects" ], "type": "object" }, "LatestDeploymentMediaResponseItem": { "properties": { "latest_attempt_status": { "type": "string" }, "project_id": { "format": "int32", "type": "integer" }, "screenshot_location": { "type": [ "string", "null" ] }, "url": { "type": [ "string", "null" ] } }, "required": [ "project_id", "latest_attempt_status" ], "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" }, "LineIndexBackend": { "description": "The stores a line index can live in, in the order the plugin prefers\nthem: the instance's own ClickHouse, then Temps Cloud's, then the\ncontrol-plane TimescaleDB.", "enum": [ "clickhouse", "temps_cloud", "timescaledb" ], "type": "string" }, "LinkApplicationProjectRequest": { "properties": { "project_id": { "format": "int32", "type": "integer" } }, "required": [ "project_id" ], "type": "object" }, "LinkServiceRequest": { "properties": { "custom_database_name": { "description": "Exact database name used when `database_provisioning_mode` is `custom`.", "type": [ "string", "null" ] }, "database_provisioning_mode": { "$ref": "#/components/schemas/DatabaseProvisioningMode", "description": "How deployments linked through this service select a logical database." }, "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, ISO 8601 (e.g. \"2024-01-15T14:30:00Z\")", "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, ISO 8601 (e.g. \"2024-01-15T14:30:00Z\")", "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" }, "ListDiscoveredRoutesQuery": { "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" }, "ListOperationsQuery": { "description": "Query parameters for `GET /operations`.", "properties": { "kind": { "oneOf": [ { "$ref": "#/components/schemas/OperationKind", "description": "Only operations of this kind." }, { "type": "null" } ] }, "page": { "description": "Page number, 1-based (default 1).", "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "page_size": { "description": "Items per page (default 20, max 100).", "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "project_id": { "description": "Only operations belonging to this project.", "format": "int32", "type": [ "integer", "null" ] }, "status": { "oneOf": [ { "$ref": "#/components/schemas/OperationStatusFilter", "description": "`running` (queued, running, waiting), `finished` (succeeded, failed,\ncancelled) or `all` (default)." }, { "type": "null" } ] } }, "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" }, "ListProviderDomainsResponse": { "description": "Domains discoverable on a provider's side for the \"import existing\ndomain\" picker.\n\n`supported: false` means this provider type has no domain-listing API at\nall (SMTP) — the UI must fall back to manual domain entry rather than\ntreat it as an error to retry. `error` is set when `supported` is `true`\nbut the live fetch still failed (network, revoked credentials); the same\nmanual-entry fallback applies, but it's worth surfacing as a warning.", "properties": { "domains": { "items": { "$ref": "#/components/schemas/ProviderDomainIdentityResponse" }, "type": "array" }, "error": { "type": [ "string", "null" ] }, "supported": { "type": "boolean" } }, "required": [ "supported", "domains" ], "type": "object" }, "ListRenewalAttemptsResponse": { "description": "Paginated renewal-attempt history for one domain, newest first.", "properties": { "attempts": { "items": { "$ref": "#/components/schemas/RenewalAttemptResponse" }, "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": [ "attempts", "total", "page", "page_size" ], "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" }, "ListSnapshotsResponse": { "description": "Paginated list of snapshots.", "properties": { "page": { "format": "int64", "minimum": 0, "type": "integer" }, "page_size": { "format": "int64", "minimum": 0, "type": "integer" }, "snapshots": { "items": { "$ref": "#/components/schemas/SnapshotResponse" }, "type": "array" }, "total": { "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "snapshots", "total", "page", "page_size" ], "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" ] }, "kind": { "oneOf": [ { "$ref": "#/components/schemas/TemplateKind", "description": "Filter by gallery (`starter` or `service`)." }, { "type": "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" }, "LocalCheckSpec": { "properties": { "warning_days": { "description": "Warn when any expiring item in the value is this close to expiry.", "items": { "format": "int32", "minimum": 0, "type": "integer" }, "type": "array" } }, "type": "object" }, "LocalCredentialDto": { "description": "Metadata about a credential that Temps can import from the server process\nuser's existing CLI login. This never includes a path or credential value.", "properties": { "auth_type": { "type": "string" }, "label": { "type": "string" }, "source": { "description": "Stable machine-readable source: `environment` or `host_auth_store`.", "type": "string" } }, "required": [ "auth_type", "source", "label" ], "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" }, "LogCollectionCapability": { "description": "Whether new container log lines are being collected right now. Separate\nfrom `analytics` because the two fail independently: after a restart the\nindex can be healthy while collection waits on WAL recovery, and without\nthis the explorer shows a histogram that simply stops.", "properties": { "collecting": { "description": "`true` only in the `running` state.", "type": "boolean" }, "deferred": { "description": "The oldest few deferred generations.", "items": { "$ref": "#/components/schemas/DeferredWalGeneration" }, "type": "array" }, "deferred_bytes": { "format": "int64", "minimum": 0, "type": "integer" }, "deferred_count": { "description": "Generations recovery set aside because it could not replay them in\nfull. Collection runs regardless; their lines are missing from search\nuntil an operator retries them.", "format": "int64", "minimum": 0, "type": "integer" }, "deferred_dir": { "description": "Directory holding them, on the server's filesystem.", "type": [ "string", "null" ] }, "deferred_error": { "description": "Set when that directory could not be read: the deferred counts and\nlist are then empty because they are unknown, not because nothing\nwas deferred.", "type": [ "string", "null" ] }, "details_visible": { "description": "`false` when the caller is not an instance administrator: `error`,\n`deferred_dir` and each generation's `reason` are then omitted, and\n`deferred_error` is generic, since they carry server filesystem paths\nand raw I/O errors. State and\ncounts are always present, so a paused collector is never hidden.", "type": "boolean" }, "error": { "description": "Why collection is paused, verbatim, for `retrying` and `stopped`.", "type": [ "string", "null" ] }, "retry_at": { "description": "When the next recovery pass starts, for `retrying`.", "format": "date-time", "type": [ "string", "null" ] }, "since": { "description": "When the current state began: recovery start for `recovering`,\nrecovery end for `running`.", "format": "date-time", "type": [ "string", "null" ] }, "state": { "$ref": "#/components/schemas/LogCollectionState" } }, "required": [ "state", "collecting", "deferred_count", "deferred_bytes", "deferred", "details_visible" ], "type": "object" }, "LogCollectionState": { "enum": [ "running", "recovering", "retrying", "stopped" ], "type": "string" }, "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.\n\nIdentity is `(timestamp, container_id, line_id)` — the store's own sort\norder, which is also the pagination key. `line_id` is serialized as a\n**string**: it is seeded from a 64-bit chunk/line encoding well past the\n2^53 an IEEE-754 double can represent exactly, so a JSON number would\nsilently lose its low digits in every JavaScript client.", "properties": { "container_id": { "description": "Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view, and is the second\ncomponent of the line's identity.", "type": "string" }, "context": { "oneOf": [ { "$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." }, { "type": "null" } ] }, "deploy_id": { "format": "int32", "type": [ "integer", "null" ] }, "fields": {}, "level": { "$ref": "#/components/schemas/LogLevel" }, "line_id": { "description": "Decimal string form of the line's `line_id`. See the type docs.", "type": "string" }, "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" }, "stream": { "$ref": "#/components/schemas/LogStream", "description": "stdout or stderr." }, "timestamp": { "type": "string" } }, "required": [ "timestamp", "level", "stream", "service", "message", "line_id" ], "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" }, "LogSourceKind": { "description": "Which family of log sources a query covers.", "enum": [ "collected", "application", "service" ], "type": "string" }, "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" }, "ManagedBackupArchiveConflict": { "description": "A service whose continuous archive (Postgres WAL-G, MariaDB binlogs) is\npinned to a source other than the managed destination. The nightly Cloud\nschedule cannot back it up: archiving must not silently move between\nsources, so every run of that service fails until the operator repoints\nit to Cloud or points its own schedule at the pinned source.", "properties": { "pinned_s3_source_id": { "format": "int32", "type": "integer" }, "pinned_s3_source_name": { "description": "Name of the pinned source, or its id as text when the row is gone.", "type": "string" }, "service_id": { "format": "int32", "type": "integer" }, "service_name": { "type": "string" }, "service_type": { "type": "string" } }, "required": [ "service_id", "service_name", "service_type", "pinned_s3_source_id", "pinned_s3_source_name" ], "type": "object" }, "ManagedBackupSchedule": { "description": "What the Cloud settings page shows about the schedule that targets the\nmanaged destination.", "properties": { "enabled": { "type": "boolean" }, "id": { "format": "int32", "type": "integer" }, "name": { "type": "string" }, "next_run": { "type": [ "string", "null" ] }, "retention_period": { "description": "Days each backup is kept before the schedule's retention deletes it.", "format": "int32", "type": "integer" }, "schedule_expression": { "type": "string" } }, "required": [ "id", "name", "schedule_expression", "retention_period", "enabled" ], "type": "object" }, "ManagedBackupSetup": { "properties": { "action": { "$ref": "#/components/schemas/ManagedBackupSetupAction" }, "archive_conflicts": { "description": "Services whose continuous archive is pinned elsewhere. Each fails\nunder the nightly Cloud schedule until repointed (ADR-044).", "items": { "$ref": "#/components/schemas/ManagedBackupArchiveConflict" }, "type": "array" }, "managed_s3_source_id": { "description": "The `s3_sources` row of the managed destination, when it exists, so a\nclient can repoint a conflicting service at it.", "format": "int32", "type": [ "integer", "null" ] }, "message": { "type": "string" }, "ready": { "type": "boolean" }, "schedule": { "oneOf": [ { "$ref": "#/components/schemas/ManagedBackupSchedule", "description": "The schedule that writes to the managed destination, when one does.\n`None` on a ready destination means nothing backs up to Cloud yet:\nthe console offers to create the nightly schedule (ADR-044)." }, { "type": "null" } ] }, "status": { "$ref": "#/components/schemas/ManagedBackupSetupStatus" } }, "required": [ "status", "ready", "message", "action", "archive_conflicts" ], "type": "object" }, "ManagedBackupSetupAction": { "enum": [ "none", "retry", "renew_subscription" ], "type": "string" }, "ManagedBackupSetupStatus": { "enum": [ "disabled", "ready", "needs_setup", "subscription_required", "unavailable" ], "type": "string" }, "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" }, "proxied_by_default": { "type": "boolean" }, "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", "proxied_by_default", "verified", "generated_hostname_mode", "sync_generated_records", "created_at", "updated_at" ], "type": "object" }, "ManagedEnvironmentVariable": { "properties": { "description": { "type": "string" }, "is_secret": { "type": "boolean" }, "is_user_overridable": { "description": "Whether a user-defined value is intentionally allowed to replace the\ngenerated default. When false, the deployment pipeline wins.", "type": "boolean" }, "name": { "type": "string" }, "source": { "$ref": "#/components/schemas/ManagedEnvironmentVariableSource" } }, "required": [ "name", "source", "is_secret", "is_user_overridable", "description" ], "type": "object" }, "ManagedEnvironmentVariableSource": { "enum": [ "error_tracking", "open_telemetry", "temps" ], "type": "string" }, "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" }, "Maturity": { "enum": [ "stable", "beta", "experimental" ], "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" }, "McpServerSettings": { "description": "MCP server settings (ADR-039).\n\nThe MCP endpoint lets AI tools (e.g. the Temps CLI wizard) interact with\nthis Temps instance through the Model Context Protocol. Disabled by\ndefault so new installs do not expose the endpoint until the operator\nexplicitly opts in.\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), `GET /mcp/tools` returns `404`\nand all other MCP endpoints return `404` too. Set to `true` via the\nSettings UI to activate the MCP server.", "example": false, "type": "boolean" } }, "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": { "attachments": { "description": "Files copied into the persistent workspace for this user turn.", "items": { "$ref": "#/components/schemas/ChatAttachmentResponse" }, "type": [ "array", "null" ] }, "content": { "type": "string" }, "created_at": { "type": "string" }, "cursor": { "description": "Stable opaque cursor for this stored message. Clients must treat this as\nan uninterpreted token and send it back through the `before` query.", "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": [ "cursor", "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" }, "Metric": { "description": "Aggregate metric for [`LogAnalytics::aggregate`].", "oneOf": [ { "properties": { "fn": { "enum": [ "count" ], "type": "string" } }, "required": [ "fn" ], "type": "object" }, { "properties": { "attr": { "type": "string" }, "fn": { "enum": [ "count_distinct" ], "type": "string" } }, "required": [ "attr", "fn" ], "type": "object" }, { "properties": { "attr": { "type": "string" }, "fn": { "enum": [ "avg" ], "type": "string" } }, "required": [ "attr", "fn" ], "type": "object" }, { "properties": { "attr": { "type": "string" }, "fn": { "enum": [ "p50" ], "type": "string" } }, "required": [ "attr", "fn" ], "type": "object" }, { "properties": { "attr": { "type": "string" }, "fn": { "enum": [ "p95" ], "type": "string" } }, "required": [ "attr", "fn" ], "type": "object" }, { "properties": { "attr": { "type": "string" }, "fn": { "enum": [ "p99" ], "type": "string" } }, "required": [ "attr", "fn" ], "type": "object" }, { "properties": { "attr": { "type": "string" }, "fn": { "enum": [ "max" ], "type": "string" } }, "required": [ "attr", "fn" ], "type": "object" }, { "properties": { "attr": { "type": "string" }, "fn": { "enum": [ "sum" ], "type": "string" } }, "required": [ "attr", "fn" ], "type": "object" } ] }, "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": [ { "$ref": "#/components/schemas/HistogramSummary", "description": "A reduced histogram summary when the bucketed metric is a histogram." }, { "type": "null" } ] }, "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": { "end_time": { "description": "Explicit window end (ISO 8601). Must be paired with `start_time`.", "type": [ "string", "null" ] }, "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\"`.\nIgnored when `start_time` and `end_time` are both set.", "type": "string" }, "start_time": { "description": "Explicit window start (ISO 8601). Must be paired with `end_time`.", "type": [ "string", "null" ] } }, "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. Token issuance initializes the\nCA when needed, so every newly minted token carries a trust pin.", "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" }, "ModelCapability": { "properties": { "default_thinking_mode_id": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "name": { "type": "string" }, "thinking_modes": { "items": { "$ref": "#/components/schemas/SelectOption" }, "type": "array" }, "tool_thinking_modes": { "description": "Optional reasoning modes valid when function tools are attached. `None`\ninherits `thinking_modes`; `Some` is a model-specific restriction.", "items": { "$ref": "#/components/schemas/SelectOption" }, "type": [ "array", "null" ] } }, "required": [ "id", "name", "thinking_modes" ], "type": "object" }, "ModelCatalogSource": { "description": "Provenance of a provider model inventory. Only live and unexpired cached\ninventories are authoritative enough to reject a saved model. Bootstrap\nand stale inventories remain useful for selectors, but must not block a\nturn because account entitlements may legitimately differ.", "enum": [ "live", "cache", "stale_cache", "bootstrap" ], "type": "string" }, "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" }, "next_check_at": { "description": "When the scheduler will next probe this monitor. Read-only: it is\nmaintained by the health-check scheduler, never accepted on write.\n`null` means the monitor has not been scheduled yet and is due on the\nnext sweep.", "format": "date-time", "type": [ "string", "null" ] }, "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": { "$ref": "#/components/schemas/MetricsStoreKind", "default": "timescale_db", "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_failover_after_secs": { "default": 300, "description": "Seconds a worker node must go without a heartbeat before its workloads\nare failed over to healthy nodes. A node is reported offline (and\noperators alerted) well before this; the gap is a grace period so a\nbrief network partition or a control-plane stall does not redeploy a\nwhole node's worth of apps that never stopped serving. `None` disables\nautomatic failover entirely. Default 300.", "format": "int64", "minimum": 0, "type": [ "integer", "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": true, "description": "Whether to enforce multi-node mTLS (ADR-020 WS-2.1). New installations\ndefault to `true`. Existing serialized settings that predate this field\ndeserialize it as `false`, providing an explicit migration window rather\nthan unexpectedly disconnecting legacy workers. 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" ] }, "cluster_network": { "oneOf": [ { "$ref": "#/components/schemas/ClusterNetworkSettings", "description": "Effective cluster-wide container address pool. `None` only when the\nsingleton network configuration could not be read." }, { "type": "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_failover_after_secs": { "description": "Seconds without a heartbeat before a node's workloads are failed over;\n`None` = automatic failover disabled.", "format": "int64", "minimum": 0, "type": [ "integer", "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" }, "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" }, "NetworkInterface": { "description": "Information about a network interface", "properties": { "address": { "description": "IP address of the interface", "type": "string" }, "interface": { "description": "Name of the network interface", "type": "string" }, "is_link_local": { "description": "Whether this is a link-local address (IPv6)", "type": [ "boolean", "null" ] }, "is_private": { "description": "Whether this is a private IP address (RFC 1918)", "type": [ "boolean", "null" ] }, "is_unique_local": { "description": "Whether this is a unique local address (IPv6)", "type": [ "boolean", "null" ] } }, "required": [ "address", "interface" ], "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" } ] }, "NetworkPoolEntry": { "description": "Cluster-wide pool which every node must use. This is intentionally sent\nalongside the local allocation so operators and agents can detect stale or\nindependently configured nodes before routes are changed.", "properties": { "compute_pool_cidr": { "type": "string" }, "subnet_prefix_len": { "format": "int32", "minimum": 0, "type": "integer" } }, "required": [ "compute_pool_cidr", "subnet_prefix_len" ], "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" }, "NodeCapabilityResponse": { "description": "Whether this installation can run a workload anywhere, and if not, why.", "properties": { "active_worker_nodes": { "description": "Worker nodes that are active and heartbeating. Excludes the control\nplane, which `local_workloads` already reports.", "format": "int32", "minimum": 0, "type": "integer" }, "can_manage_nodes": { "description": "Whether *this caller* can act on `setup_path`.\n\nThe capability itself is readable by every authenticated session, but\nthe remedy is not: the Worker Nodes page needs `SettingsRead` to list\nthe node inventory and `SettingsWrite` to mint an enrollment token.\nSending a caller without both to that page produces \"Failed to load\nworker nodes\" — an advertised fix that denies the user who followed it.\nClients render a non-admin variant (\"ask an administrator\") when this\nis false rather than a dead link.", "type": "boolean" }, "local_workloads": { "description": "Whether the control plane itself may run containers, builds and\nmanaged services (false in the `control-plane` serve profile).", "type": "boolean" }, "reason": { "description": "Why nothing can be placed, when `schedulable` is false. Rendered\nverbatim by the client.", "type": [ "string", "null" ] }, "schedulable": { "description": "Whether a workload can be placed at all.", "type": "boolean" }, "setup_path": { "description": "Console path that fixes it: where an operator joins a worker node.", "type": "string" } }, "required": [ "local_workloads", "active_worker_nodes", "schedulable", "setup_path", "can_manage_nodes" ], "type": "object" }, "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" }, "NodeDnsStatusEntry": { "description": "Per-node DNS resolver health, as last reported by that node's heartbeat.\nPart of `GET /api/cluster/dns/status`.", "properties": { "dns_resolver_consecutive_failures": { "format": "int32", "type": "integer" }, "dns_resolver_last_error": { "type": [ "string", "null" ] }, "dns_resolver_last_sync_at": { "type": [ "string", "null" ] }, "dns_resolver_record_count": { "format": "int32", "type": [ "integer", "null" ] }, "dns_resolver_running": { "description": "`None` = never reported (older agent, or a single-host node that\nnever allocates a `compute_cidr` and so never touches cluster DNS).", "type": [ "boolean", "null" ] }, "dns_resolver_tasks_alive": { "type": [ "boolean", "null" ] }, "node_id": { "format": "int32", "type": "integer" }, "node_name": { "type": "string" }, "node_status": { "description": "The node's own status field (`active`, `offline`, `draining`, …) —\nincluded so an operator can tell \"resolver down\" apart from \"node\ndown\" at a glance, without a second request.", "type": "string" }, "seconds_since_last_sync": { "description": "Computed from `dns_resolver_last_sync_at` against \"now\" server-side —\na raw timestamp makes an operator do the subtraction themselves for\nevery node; a staleness age is what actually answers \"is this\nhealthy right now\". `None` when `dns_resolver_last_sync_at` is `None`.", "format": "int64", "type": [ "integer", "null" ] } }, "required": [ "node_id", "node_name", "node_status", "dns_resolver_consecutive_failures" ], "type": "object" }, "NodeEvictionIncompleteProblem": { "description": "RFC 7807 body of a `503` from `POST /v1/sandboxes/placement/nodes/{node}/evict`\nwhen some sandboxes could not be destroyed. Carries the same per-sandbox\ndetail as a successful eviction, as Problem extension members.", "properties": { "containers_unconfirmed": { "description": "Destroyed sandboxes whose container the node did not confirm\nremoving, with the command to remove it on the node.", "items": { "$ref": "#/components/schemas/EvictionUnconfirmedContainer" }, "type": "array" }, "destroyed": { "description": "Public ids of the sandboxes destroyed by this eviction.", "items": { "type": "string" }, "type": "array" }, "detail": { "type": "string" }, "failed": { "description": "Sandboxes that could not be destroyed. Running the eviction again\nretries them.", "items": { "$ref": "#/components/schemas/EvictionFailedSandbox" }, "type": "array" }, "status": { "format": "int32", "minimum": 0, "type": "integer" }, "title": { "type": "string" }, "type": { "description": "`https://temps.sh/probs/sandbox-node-eviction-incomplete`", "type": "string" } }, "required": [ "type", "title", "status", "detail", "destroyed", "containers_unconfirmed", "failed" ], "type": "object" }, "NodeEvictionResponse": { "description": "`POST /v1/sandboxes/placement/nodes/{node}/evict`", "properties": { "containers_unconfirmed": { "description": "Destroyed sandboxes whose container the node did not confirm\nremoving: it may still be running there. Check the node, or remove\nit if it is gone for good.", "items": { "$ref": "#/components/schemas/EvictionUnconfirmedContainer" }, "type": "array" }, "destroyed": { "description": "Public ids of the sandboxes destroyed (their rows are gone, and they\nno longer block removing the node).", "items": { "type": "string" }, "type": "array" }, "node": { "$ref": "#/components/schemas/PlacementNode" } }, "required": [ "node", "destroyed", "containers_unconfirmed" ], "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" }, "public_ingress_certificate_count": { "format": "int32", "type": [ "integer", "null" ] }, "public_ingress_enabled": { "type": "boolean" }, "public_ingress_last_error": { "type": [ "string", "null" ] }, "public_ingress_route_count": { "format": "int32", "type": [ "integer", "null" ] }, "public_ingress_running": { "type": [ "boolean", "null" ] }, "public_ingress_unsupported_reasons": { "items": { "type": "string" }, "type": "array" }, "public_ingress_unsupported_route_count": { "format": "int32", "type": [ "integer", "null" ] }, "role": { "type": "string" }, "status": { "type": "string" } }, "required": [ "id", "name", "address", "private_address", "role", "status", "labels", "capacity", "created_at", "public_ingress_enabled", "public_ingress_unsupported_reasons" ], "type": "object" }, "NodeListResponse": { "properties": { "nodes": { "items": { "$ref": "#/components/schemas/NodeInfoResponse" }, "type": "array" }, "total": { "minimum": 0, "type": "integer" } }, "required": [ "nodes", "total" ], "type": "object" }, "NodePairingListResponse": { "properties": { "pairings": { "items": { "$ref": "#/components/schemas/NodePairingResponse" }, "type": "array" } }, "required": [ "pairings" ], "type": "object" }, "NodePairingResponse": { "description": "A pairing as the Worker Nodes page shows it.", "properties": { "created_at": { "type": "string" }, "expires_at": { "type": "string" }, "id": { "format": "int32", "type": "integer" }, "last_attempt_at": { "type": [ "string", "null" ] }, "last_error": { "description": "Why the last attempt to reach the node failed.", "type": [ "string", "null" ] }, "last_rejection": { "description": "Why the control plane last refused the node's key (e.g. it belongs to\nanother node). Kept until a key is accepted, so it outlives the\n\"no answer\" attempts after the refused node stopped.", "type": [ "string", "null" ] }, "mesh_address": { "description": "Mesh address reserved for the node.", "type": "string" }, "name": { "type": "string" }, "node_endpoint": { "description": "`ip:port` the control plane dials.", "type": "string" }, "node_id": { "description": "The node that registered with this pairing.", "format": "int32", "type": [ "integer", "null" ] }, "status": { "description": "`waiting` (dialing the node), `key_received` (the node answered; it is\nregistering over the mesh), `completed`, `expired` or `cancelled`.", "type": "string" } }, "required": [ "id", "name", "node_endpoint", "mesh_address", "status", "expires_at", "created_at" ], "type": "object" }, "NodeSandboxEntry": { "description": "A live sandbox on a node, with its owner. For sandboxes the caller does\nnot own, owner-only details (preview password hint, source repository\nURL) are omitted.", "properties": { "owner_email": { "description": "Owner's email, when the owner is a user that still exists.", "type": [ "string", "null" ] }, "owner_user_id": { "format": "int32", "type": [ "integer", "null" ] }, "sandbox": { "$ref": "#/components/schemas/SandboxInner" } }, "required": [ "sandbox" ], "type": "object" }, "NodeSandboxesResponse": { "description": "`GET /v1/sandboxes/placement/nodes/{node}` — every live sandbox on one\nnode, whoever owns it.", "properties": { "node": { "$ref": "#/components/schemas/PlacementNode" }, "page": { "format": "int64", "minimum": 0, "type": "integer" }, "page_size": { "format": "int64", "minimum": 0, "type": "integer" }, "sandboxes": { "description": "One page, newest first.", "items": { "$ref": "#/components/schemas/NodeSandboxEntry" }, "type": "array" }, "total": { "description": "Every live sandbox on the node, across all pages.", "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "node", "sandboxes", "total", "page", "page_size" ], "type": "object" }, "NodeSshCredentials": { "description": "How to log in to the server. Used for this enrollment only, never stored.\nIts `Debug` never prints the credentials.", "oneOf": [ { "description": "The user's password; also used for `sudo` if it asks for one.", "properties": { "method": { "enum": [ "password" ], "type": "string" }, "password": { "type": "string" } }, "required": [ "password", "method" ], "type": "object" }, { "description": "An OpenSSH or PEM private key, with its passphrase if it has one.", "properties": { "method": { "enum": [ "private_key" ], "type": "string" }, "passphrase": { "type": [ "string", "null" ] }, "private_key": { "type": "string" } }, "required": [ "private_key", "method" ], "type": "object" }, { "description": "The SSH agent of the control plane's `temps serve` process.", "properties": { "method": { "enum": [ "agent" ], "type": "string" } }, "required": [ "method" ], "type": "object" } ] }, "NodeSshEnrollmentCreateRequest": { "description": "Add a server over SSH.", "properties": { "credentials": { "$ref": "#/components/schemas/NodeSshCredentials" }, "host": { "description": "Hostname or IP address.", "type": "string" }, "host_key_fingerprint": { "description": "The host-key fingerprint the operator confirmed (from\n`POST /nodes/ssh/host-key`). The enrollment stops if the server\npresents another key.", "type": "string" }, "name": { "description": "Name the node registers under. Defaults to `worker-`.", "type": [ "string", "null" ] }, "node_address": { "description": "The server's public address for WireGuard, `ip` or `ip:port`, when it\nis not the address SSH connects to.", "type": [ "string", "null" ] }, "port": { "description": "SSH port (default 22).", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "user": { "description": "User to log in as: root, or a user with sudo.", "type": "string" } }, "required": [ "host", "user", "credentials", "host_key_fingerprint" ], "type": "object" }, "NodeSshEnrollmentListResponse": { "description": "A page of servers added over SSH, newest first.", "properties": { "enrollments": { "items": { "$ref": "#/components/schemas/NodeSshEnrollmentSummary" }, "type": "array" }, "page": { "format": "int64", "minimum": 0, "type": "integer" }, "per_page": { "format": "int64", "minimum": 0, "type": "integer" }, "total": { "description": "Enrollments on every page.", "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "enrollments", "total", "page", "per_page" ], "type": "object" }, "NodeSshEnrollmentResponse": { "description": "An \"add server over SSH\" as the Worker Nodes page shows it.", "properties": { "agent_mode": { "description": "`service` (systemd unit) or `detached` (started without a service\nmanager: it does not come back after a reboot).", "type": [ "string", "null" ] }, "auth_method": { "description": "`password`, `private_key` or `agent`.", "type": "string" }, "created_at": { "type": "string" }, "error": { "description": "Why it failed, and what to do.", "type": [ "string", "null" ] }, "finished_at": { "type": [ "string", "null" ] }, "host": { "type": "string" }, "host_key_fingerprint": { "type": "string" }, "id": { "format": "int32", "type": "integer" }, "log": { "description": "What it did, with the server's output (its last 64 KiB).", "type": "string" }, "name": { "type": "string" }, "node_id": { "format": "int32", "type": [ "integer", "null" ] }, "pairing_id": { "description": "The pairing it runs on the server.", "format": "int32", "type": [ "integer", "null" ] }, "ssh_address": { "type": "string" }, "ssh_user": { "type": "string" }, "status": { "description": "`running`, `succeeded` or `failed`.", "type": "string" }, "step": { "description": "What it is doing, or was doing when it stopped.", "type": "string" } }, "required": [ "id", "name", "host", "ssh_address", "ssh_user", "auth_method", "host_key_fingerprint", "status", "step", "log", "created_at" ], "type": "object" }, "NodeSshEnrollmentSummary": { "description": "An \"add server over SSH\" in a list: everything but its log, which\n`GET /nodes/ssh/enrollments/{enrollment_id}` returns.", "properties": { "agent_mode": { "description": "`service` or `detached`.", "type": [ "string", "null" ] }, "auth_method": { "description": "`password`, `private_key` or `agent`.", "type": "string" }, "created_at": { "type": "string" }, "error": { "description": "Why it failed, and what to do.", "type": [ "string", "null" ] }, "finished_at": { "type": [ "string", "null" ] }, "host": { "type": "string" }, "host_key_fingerprint": { "type": "string" }, "id": { "format": "int32", "type": "integer" }, "name": { "type": "string" }, "node_id": { "format": "int32", "type": [ "integer", "null" ] }, "pairing_id": { "description": "The pairing it runs on the server.", "format": "int32", "type": [ "integer", "null" ] }, "ssh_address": { "type": "string" }, "ssh_user": { "type": "string" }, "status": { "description": "`running`, `succeeded` or `failed`.", "type": "string" }, "step": { "description": "What it is doing, or was doing when it stopped.", "type": "string" } }, "required": [ "id", "name", "host", "ssh_address", "ssh_user", "auth_method", "host_key_fingerprint", "status", "step", "created_at" ], "type": "object" }, "NodeSshHostKeyRequest": { "description": "A server to read the SSH host key of.", "properties": { "host": { "description": "Hostname or IP address.", "type": "string" }, "port": { "description": "SSH port (default 22).", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] } }, "required": [ "host" ], "type": "object" }, "NodeSshHostKeyResponse": { "description": "The server's SSH host key. Compare the fingerprint with the server's\n(`ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub` on it) before\nenrolling it.", "properties": { "address": { "description": "`ip:port` the control plane connected to.", "type": "string" }, "algorithm": { "description": "e.g. `ssh-ed25519`.", "type": "string" }, "fingerprint": { "description": "`SHA256:…`, as `ssh-keygen -l` prints it.", "type": "string" } }, "required": [ "address", "algorithm", "fingerprint" ], "type": "object" }, "NotificationDeliveryCoverageResponse": { "description": "Whether a notification of one severity would reach anyone, with the\nconsole page that fixes it when it would not.", "properties": { "cloud_delivery": { "description": "Whether Temps Cloud also delivers notifications from this instance.", "type": "boolean" }, "configured": { "description": "Whether at least one destination would receive the notification.", "type": "boolean" }, "provider_ids": { "description": "Enabled providers those routes deliver to.", "items": { "format": "int32", "type": "integer" }, "type": "array" }, "reason": { "description": "Why nothing would be delivered, when `configured` is false.", "type": [ "string", "null" ] }, "route_ids": { "description": "Enabled routes whose severity range contains `severity`.", "items": { "format": "int32", "type": "integer" }, "type": "array" }, "setup_path": { "description": "Console path that fixes the gap, when `configured` is false.", "type": [ "string", "null" ] }, "severity": { "type": "string" } }, "required": [ "severity", "configured", "route_ids", "provider_ids", "cloud_delivery" ], "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" }, "NotificationRoute": { "properties": { "created_at": { "format": "int64", "type": "integer" }, "enabled": { "type": "boolean" }, "id": { "format": "int32", "type": "integer" }, "max_severity": { "type": "string" }, "min_severity": { "type": "string" }, "name": { "type": "string" }, "provider_ids": { "items": { "format": "int32", "type": "integer" }, "type": "array" }, "updated_at": { "format": "int64", "type": "integer" } }, "required": [ "id", "name", "enabled", "min_severity", "max_severity", "provider_ids", "created_at", "updated_at" ], "type": "object" }, "NotificationRoutePage": { "properties": { "items": { "items": { "$ref": "#/components/schemas/NotificationRoute" }, "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" }, "NotificationRouteTestResult": { "properties": { "deliveries": { "items": { "$ref": "#/components/schemas/RouteTestDelivery" }, "type": "array" }, "route_enabled": { "description": "A disabled route is still tested, but real notifications skip it.", "type": "boolean" }, "route_id": { "format": "int32", "type": "integer" }, "route_name": { "type": "string" }, "severity": { "description": "Severity of the sample notification: the lowest one the route matches.", "type": "string" } }, "required": [ "route_id", "route_name", "route_enabled", "severity", "deliveries" ], "type": "object" }, "NumericRule": { "properties": { "comparison": { "$ref": "#/components/schemas/Comparison" }, "critical": { "format": "double", "type": [ "number", "null" ] }, "field": { "$ref": "#/components/schemas/ResponseField" }, "name": { "type": "string" }, "warning": { "format": "double", "type": "number" } }, "required": [ "name", "field", "comparison", "warning" ], "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": { "container_logs_days": { "default": 30, "description": "Retain collected container logs (chunk objects on disk/S3, their\nmanifest rows, and the ClickHouse line index when configured) for\nthis many days.", "example": 30, "format": "int32", "maximum": 3650, "minimum": 1, "type": "integer" }, "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" }, "managed_by_cloud": { "description": "ADR-045 §4: true only for the provider Temps Cloud provisions for\nconsole access. The admin UI should disable edit/delete controls for\nsuch a row — the API itself refuses those requests regardless\n(`OidcError::ManagedByCloudEdit`/`ManagedByCloudDelete`).", "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", "managed_by_cloud" ], "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" }, "OperationEntry": { "description": "One operation in the feed.", "properties": { "agent_run_id": { "format": "int32", "type": [ "integer", "null" ] }, "backup_id": { "format": "int32", "type": [ "integer", "null" ] }, "created_at": { "format": "date-time", "type": "string" }, "deployment_id": { "format": "int32", "type": [ "integer", "null" ] }, "environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "environment_name": { "type": [ "string", "null" ] }, "failure_reason": { "description": "Why the operation failed or was cancelled, when known.", "type": [ "string", "null" ] }, "finished_at": { "format": "date-time", "type": [ "string", "null" ] }, "id": { "description": "Stable unique id, `:` (e.g. `deployment:123`).", "type": "string" }, "kind": { "$ref": "#/components/schemas/OperationKind" }, "link": { "description": "Console path of the resource's detail page.", "type": "string" }, "phase": { "description": "Source-specific phase, when the source records one (restores, autofix).", "type": [ "string", "null" ] }, "project_id": { "description": "Owning project. For restores and backups this is set only when the\nservice is linked to exactly one project.", "format": "int32", "type": [ "integer", "null" ] }, "project_slug": { "type": [ "string", "null" ] }, "restore_run_id": { "format": "int32", "type": [ "integer", "null" ] }, "service_id": { "description": "Storage service the operation acts on (the restore's source service,\nor the backed-up service).", "format": "int32", "type": [ "integer", "null" ] }, "service_name": { "type": [ "string", "null" ] }, "started_at": { "format": "date-time", "type": [ "string", "null" ] }, "status": { "$ref": "#/components/schemas/OperationStatus" }, "title": { "description": "Human-readable label, e.g. \"Rollback to deployment #41\".", "type": "string" }, "triggered_by_user_id": { "description": "User who started it, when the source records one. Deployments do not.", "format": "int32", "type": [ "integer", "null" ] } }, "required": [ "id", "kind", "status", "title", "created_at", "link" ], "type": "object" }, "OperationKind": { "description": "What kind of operation an entry describes.", "enum": [ "deployment", "rollback", "promotion", "restore", "backup", "autofix" ], "type": "string" }, "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" }, "OperationStatus": { "description": "Normalised lifecycle state of an operation.", "enum": [ "queued", "running", "waiting", "succeeded", "failed", "cancelled" ], "type": "string" }, "OperationStatusFilter": { "description": "Which slice of the feed to return.", "enum": [ "running", "finished", "all" ], "type": "string" }, "OperationsListResponse": { "description": "A page of the operations feed. Sorted by `created_at` descending (fixed).", "properties": { "operations": { "items": { "$ref": "#/components/schemas/OperationEntry" }, "type": "array" }, "page": { "format": "int64", "minimum": 0, "type": "integer" }, "page_size": { "format": "int64", "minimum": 0, "type": "integer" }, "running_count": { "description": "Queued, running and waiting operations matching the scope, `kind` and\n`project_id` filters — independent of the `status` filter, so the tray\nbadge stays correct while browsing finished operations.", "format": "int64", "minimum": 0, "type": "integer" }, "total": { "description": "Operations matching every filter.", "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "operations", "total", "page", "page_size", "running_count" ], "type": "object" }, "OriginTlsPolicy": { "enum": [ "existing_certificate" ], "type": "string" }, "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" ] }, "container_name": { "description": "Docker container name for this instance's gateway; empty resets it\nto the default. Change it only when several Temps instances share one\nDocker daemon: each needs its own name and host port. A new name\nfirst removes this instance's gateway under the old one, and while\nthe gateway is enabled it is then created under the new one. Refused\nwhile this host has sandboxes: their networks keep the current name.", "type": [ "string", "null" ] }, "enabled": { "description": "Turn the gateway off (its containers are removed at once, so preview\nURLs stop being served) or on (it is created again).", "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": [ { "$ref": "#/components/schemas/AllocEntry", "description": "Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet." }, { "type": "null" } ] }, "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" }, "network": { "$ref": "#/components/schemas/NetworkPoolEntry" }, "peers": { "description": "All other nodes with a `compute_cidr` set, excluding the caller.", "items": { "$ref": "#/components/schemas/PeerEntry" }, "type": "array" }, "wireguard": { "oneOf": [ { "$ref": "#/components/schemas/WireguardMeshEntry", "description": "Managed WireGuard mesh, when enabled on the cluster." }, { "type": "null" } ] } }, "required": [ "network", "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" }, "PermissionDecision": { "description": "The user's decision for a pending permission request. Serialized as a tagged\nJSON object and sent in the resolve endpoint body. `DenyTool`/`RejectPlan`\ncarry an optional human-readable reason that is forwarded to the CLI's\n`control_response` (never stored).", "oneOf": [ { "description": "Allow the tool to run as requested (milestone 3).", "properties": { "type": { "enum": [ "allow_tool" ], "type": "string" } }, "required": [ "type" ], "type": "object" }, { "description": "Deny the tool, with an optional explanation for the model (milestone 3).", "properties": { "reason": { "type": [ "string", "null" ] }, "type": { "enum": [ "deny_tool" ], "type": "string" } }, "required": [ "type" ], "type": "object" }, { "description": "Answer an `AskUserQuestion` prompt (milestone 4). `answers` is a JSON\nobject mapping the literal question text to the chosen option label or\nfree-text answer, per the confirmed wire protocol.", "properties": { "answers": {}, "type": { "enum": [ "answer_question" ], "type": "string" } }, "required": [ "answers", "type" ], "type": "object" }, { "description": "Approve an `ExitPlanMode` plan (milestone 5).", "properties": { "type": { "enum": [ "approve_plan" ], "type": "string" } }, "required": [ "type" ], "type": "object" }, { "description": "Reject an `ExitPlanMode` plan with optional feedback (milestone 5).", "properties": { "feedback": { "type": [ "string", "null" ] }, "type": { "enum": [ "reject_plan" ], "type": "string" } }, "required": [ "type" ], "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" }, "PermissionKind": { "description": "Kind of permission the Claude CLI is requesting via `--permission-prompt-tool stdio`\n(ADR-038 Phase 2). Used to drive the correct UI card (`ToolApproval` → allow/deny\nbuttons; `Question` → answer form; `PlanApproval` → approve/reject-with-feedback).", "enum": [ "tool_approval", "question", "plan_approval" ], "type": "string" }, "PermissionRequest": { "description": "A permission request emitted by `run_interactive` when the Claude CLI blocks\non a `control_request` frame. Passed to the UI via an SSE event so the user\ncan respond before the subprocess continues.", "properties": { "id": { "description": "The CLI's own `request_id` (UUID); used as the key in the pending-permission\nregistry and as `{permission_id}` in the resolve endpoint.", "type": "string" }, "input": { "description": "Raw `request.input` from the CLI — passed through to the UI verbatim so\neach milestone's card can render the relevant fields without requiring the\nservice layer to know about tool-specific schemas." }, "kind": { "$ref": "#/components/schemas/PermissionKind", "description": "What kind of interaction is required." }, "tool_name": { "description": "The tool name from `request.tool_name` (e.g. `\"Bash\"`, `\"AskUserQuestion\"`).", "type": "string" } }, "required": [ "id", "kind", "tool_name", "input" ], "type": "object" }, "PermissionRequestedEvent": { "description": "Payload for the `permission_requested` SSE event (ADR-038 Phase 2).\nThe active provider turn is paused waiting for the user to approve or deny\na tool/question/plan. Resolve via\n`POST .../permissions/{id}/resolve`.", "properties": { "id": { "description": "The CLI's `request_id` — also the `{permission_id}` in the resolve URL.", "type": "string" }, "input": { "description": "Raw `input` from the CLI request. Passed through verbatim so each\nmilestone's card can render tool-specific fields without the service\nlayer needing to know about their schemas." }, "kind": { "$ref": "#/components/schemas/PermissionKind", "description": "What kind of interaction is required: `\"tool_approval\"`, `\"question\"`,\nor `\"plan_approval\"`." }, "tool_name": { "description": "Tool name from the CLI request (e.g. `\"Bash\"`, `\"AskUserQuestion\"`).", "type": "string" } }, "required": [ "id", "kind", "tool_name", "input" ], "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" }, "PipelineHistoryPoint": { "description": "One `(timestamp, value)` sample in a pipeline series.", "properties": { "time": { "description": "ISO 8601 timestamp with `Z` suffix (bucket start).", "type": "string" }, "value": { "description": "Bucket value — the mean per-sample delta, see [`PipelineSeries`].", "format": "double", "type": "number" } }, "required": [ "time", "value" ], "type": "object" }, "PipelineHistoryResponse": { "description": "Time-series history for every counter the pipeline-stats sampler publishes.", "properties": { "end_time": { "description": "Resolved window end (ISO 8601, `Z`).", "type": "string" }, "sample_interval_seconds": { "description": "Interval the sampler writes at, in seconds. The client needs this to\nlabel values honestly: a bucket is the *mean delta per sample*, so\n\"events per `sample_interval_seconds`\", not a bucket total.", "format": "int64", "type": "integer" }, "series": { "description": "One entry per sampled counter, always the full set in a stable order —\na counter with no data yet is present with an empty `points`, never\nomitted, so the client can render an empty chart instead of dropping\nthe panel.", "items": { "$ref": "#/components/schemas/PipelineSeries" }, "type": "array" }, "start_time": { "description": "Resolved window start (ISO 8601, `Z`).", "type": "string" }, "step_seconds": { "description": "Bucket width actually used, in seconds. Server-derived from the window\nso a caller cannot request 1-minute buckets over 7 days.", "format": "int64", "type": "integer" } }, "required": [ "series", "start_time", "end_time", "step_seconds", "sample_interval_seconds" ], "type": "object" }, "PipelineSeries": { "description": "One charted counter over the requested window.", "properties": { "name": { "description": "Metric name, e.g. `otel.spans_dropped`.", "type": "string" }, "points": { "description": "Buckets in ascending time order. Empty when the window predates the\nfirst sample (a freshly started server has no history yet).", "items": { "$ref": "#/components/schemas/PipelineHistoryPoint" }, "type": "array" } }, "required": [ "name", "points" ], "type": "object" }, "PipelineStats": { "description": "Internal pipeline statistics for self-observability.\n\nAll fields are cumulative process-lifetime counters. Every one of them is\nalso sampled every 60 seconds by the plugin's stats sampler and written to\nthe unified metrics store as a **delta** counter named `otel.`\n(`SourceKind::Node`, node_id 0) — see `pipeline_stat_deltas` in\n`plugin.rs`. Adding a field here means adding it there too, otherwise the\nnew counter is only ever visible through the API response.", "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" }, "quota_exceeded_requests": { "description": "Cumulative count of ingest requests rejected because the per-project\nstorage quota was exceeded (→ HTTP 413). Written to the metrics store\nas `otel.quota_exceeded_requests` (SourceKind::Node, node_id 0) every 60s.", "format": "int64", "minimum": 0, "type": "integer" }, "rate_limited_requests": { "description": "Cumulative count of ingest requests rejected because the per-project\nrate limit was exceeded (→ HTTP 429). Written to the metrics store as\n`otel.rate_limited_requests` (SourceKind::Node, node_id 0) every 60s.", "format": "int64", "minimum": 0, "type": "integer" }, "relay_dropped_batches": { "description": "Cumulative count of best-effort relay batches rejected because the\nbounded relay handoff was saturated or closed.", "format": "int64", "minimum": 0, "type": "integer" }, "relay_dropped_items": { "description": "Cumulative signal-item count contained in rejected relay batches.", "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", "rate_limited_requests", "quota_exceeded_requests", "relay_dropped_batches", "relay_dropped_items" ], "type": "object" }, "PipelineStatsResponse": { "properties": { "stats": { "$ref": "#/components/schemas/PipelineStats" } }, "required": [ "stats" ], "type": "object" }, "PlacementNode": { "description": "One row of `GET /sandboxes/placement`.", "properties": { "allowed": { "description": "Allowed by the operator's sandbox placement settings.", "type": "boolean" }, "eligible": { "description": "Can take a new sandbox right now (allowed and active).", "type": "boolean" }, "id": { "description": "Node id; `0` for the control plane.", "format": "int32", "type": "integer" }, "is_control_plane": { "type": "boolean" }, "live_sandboxes": { "description": "Sandboxes currently hosted on the node (not destroyed).", "format": "int64", "minimum": 0, "type": "integer" }, "name": { "type": "string" }, "reason": { "description": "Why the node is not eligible, when it isn't.", "type": [ "string", "null" ] }, "status": { "description": "Node status (`active`, `offline`, `draining`, …). Always `active`\nfor the control plane.", "type": "string" } }, "required": [ "id", "name", "is_control_plane", "status", "allowed", "eligible", "live_sandboxes" ], "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\", \"mariadb_physical\", \"mariadb_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" }, "PlatformFeatures": { "description": "Which capabilities this server process actually provides.\n\nA client cannot tell \"this build has no sandboxes\" from \"this process was\nstarted in a profile that does not run them\" by probing endpoints — both\nlook like failure. This endpoint answers the question directly so the\nconsole can render an honest, actionable state (what is unavailable, and\nwhy) instead of a dead button or an empty page.\n\n**Honesty contract**: every field that is `true` MUST be backed by a\nregistered, reachable subsystem. A `true` that is not true is worse than\nthe endpoint not existing — it causes the console to render controls that\nsilently fail instead of showing an onboarding state.", "properties": { "backups_local": { "description": "Backups can be produced from services running on this host.\nRemote backups of worker-node services are reported separately in\n[`backups_remote`][Self::backups_remote].", "type": "boolean" }, "backups_remote": { "description": "Backups of services on worker nodes can be orchestrated, scheduled and\nretained by this process. `true` when the backup scheduler is\nconfigured and worker credentials are present, regardless of profile.", "type": "boolean" }, "deployments_local": { "description": "Application containers can run on this host. `false` in the\n`control-plane` profile: applications run on worker nodes joined with\n`temps join`.", "type": "boolean" }, "docker": { "description": "Whether a Docker client exists AND a daemon answered a ping at startup.\nIn the `control-plane` profile a daemon may still be present for\ndiagnostics, but no workloads are placed here regardless.", "type": "boolean" }, "external_plugins": { "description": "External plugin binaries and plugin-owned files may be installed.", "type": "boolean" }, "image_builds_local": { "description": "Container images can be built by this process. Requires a local Docker\ndaemon; always `false` when `docker` is `false`.", "type": "boolean" }, "imports": { "description": "Workload importers (Compose, Coolify, Dokploy, Portainer, Kamal,\nCapRover) are available. Requires a local Docker daemon to run importer\ncontainers.", "type": "boolean" }, "kv": { "description": "Managed key-value store is registered and reachable.", "type": "boolean" }, "log_aggregation": { "description": "Structured log aggregation, search and tailing is active.", "type": "boolean" }, "managed_services": { "description": "Managed services (PostgreSQL, Redis, MariaDB, …) can be provisioned on\nthis host. Requires a local Docker daemon.", "type": "boolean" }, "persistent_workspaces": { "description": "AI editing workspaces and chat attachments have durable local storage.", "type": "boolean" }, "profile": { "description": "Serve profile this process was started with: `\"full\"` or\n`\"control-plane\"`.", "type": "string" }, "sandboxes": { "description": "Agent sandboxes / workspace previews run in this process. Requires a\nlocal Docker daemon.", "type": "boolean" }, "stateless": { "description": "This installation uses Postgres, injected secrets and S3 for durable\nstate; its control-plane scratch disk may be discarded.", "type": "boolean" }, "vulnerability_scanning": { "description": "Container image vulnerability scanning is available. Requires a local\nDocker daemon to pull and scan images.", "type": "boolean" } }, "required": [ "profile", "docker", "deployments_local", "image_builds_local", "managed_services", "backups_local", "backups_remote", "sandboxes", "kv", "imports", "log_aggregation", "vulnerability_scanning" ], "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" }, "PluginGrantConfig": { "properties": { "ai_daily_call_limit": { "format": "int32", "minimum": 0, "type": "integer" }, "ai_max_output_tokens": { "format": "int32", "minimum": 0, "type": "integer" }, "permissions": { "items": { "$ref": "#/components/schemas/PluginHostPermission" }, "type": "array" } }, "required": [ "permissions", "ai_daily_call_limit", "ai_max_output_tokens" ], "type": "object" }, "PluginHostPermission": { "description": "Host-owned permissions granted to one durable external-plugin actor.", "enum": [ "ai_generate", "projects_read", "environments_read", "deployments_read", "api_read", "api_write", "events_read" ], "type": "string" }, "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" ] }, "dockerfile_path": { "description": "Repository-root-relative path to the Dockerfile, when it does not\nlive directly under `{path}/Dockerfile` (e.g. `docker/Dockerfile`\nrolled up to a `path` of `\"./\"`). `None` for a Dockerfile located\ndirectly at `{path}/Dockerfile` and for every non-Dockerfile preset.", "type": [ "string", "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" }, "PreviewDomainDeliveryBindingRequest": { "properties": { "delivery_profile_id": { "format": "int32", "type": [ "integer", "null" ] }, "dns_provider_id": { "format": "int32", "type": "integer" }, "environment_id": { "format": "int32", "type": "integer" }, "hostname": { "type": "string" }, "origin_target": { "type": "string" }, "zone": { "type": "string" } }, "required": [ "hostname", "environment_id", "dns_provider_id", "zone", "origin_target" ], "type": "object" }, "PreviewGatewayLogsResponse": { "properties": { "lines": { "items": { "type": "string" }, "type": "array" } }, "required": [ "lines" ], "type": "object" }, "PreviewGatewaySettings": { "description": "Workspace preview gateway settings.\n\nThe preview gateway uses a private routing container plus a hardened ingress\nrelay bound to host loopback. The router joins each sandbox's isolated\nnetwork and routes requests to workspace dev servers based on the `Host`\nheader (`ws--.`), while the relay never joins a\ntenant network. `temps serve` reconciles both containers on startup; these\nsettings let an operator override the router image, host port, and\nauto-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" }, "container_name": { "default": "temps-preview-gateway", "description": "Docker container name for this instance's gateway.\n\nA single Temps install owns the whole host, so the default is fine and\noperators never need to touch this. It exists for the case where\nseveral Temps instances share one Docker daemon — most obviously a\ndevelopment machine with multiple checkouts running at once.\n\nWithout it those instances silently fight: the `shared_secret` is\nper-database, so each generates a different one, but they all\nreconcile the *same* container name. Each start-up sees the other's\ncontainer as drifted, recreates it with its own secret, and every\nother instance's previews start failing with \"missing or invalid\nX-Temps-Preview-Token\". Giving each instance its own container name\n(and `host_port`) makes them independent.", "example": "temps-preview-gateway", "type": "string" }, "enabled": { "default": true, "description": "Whether Temps runs the shared preview gateway. While false its\ncontainers are removed, so workspace preview URLs are not served.", "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": "", "description": "Docker image reference. Empty follows this Temps release's digest;\na nonempty value is an explicit operator pin.", "example": "ghcr.io/gotempsh/temps-preview-gateway@sha256:02d5cdd382c3285d569032e84321d5ce8fc089372a3f08651119f6eda8cb1448", "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" }, "container_name": { "description": "Docker container name of this instance's gateway.", "type": "string" }, "default_container_name": { "description": "The default container name. Only installs that share one Docker\ndaemon with another Temps instance need a different one.", "type": "string" }, "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" }, "enabled": { "description": "Whether Temps runs the gateway. While false its containers are\nremoved and workspace preview URLs are not served.", "type": "boolean" }, "host_port": { "format": "int32", "minimum": 0, "type": "integer" }, "image": { "type": "string" } }, "required": [ "enabled", "image", "host_port", "auto_upgrade", "container_name", "default_image", "default_host_port", "default_container_name" ], "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" }, "PrivateIpInfo": { "description": "Information about private/local IP addresses", "properties": { "ipv4_addresses": { "description": "All IPv4 addresses found on non-loopback interfaces", "items": { "$ref": "#/components/schemas/NetworkInterface" }, "type": "array" }, "ipv6_addresses": { "description": "All IPv6 addresses found on non-loopback interfaces", "items": { "$ref": "#/components/schemas/NetworkInterface" }, "type": "array" }, "primary_ip": { "description": "The primary private IP address (most likely to be useful)", "type": [ "string", "null" ] } }, "required": [ "ipv4_addresses", "ipv6_addresses" ], "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" ] }, "status": { "description": "HTTP status code generated by the origin server for this occurrence", "format": "int32", "minimum": 0, "type": [ "integer", "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" }, "ProjectCloudTelemetryResponse": { "description": "A project's Cloud telemetry configuration, in every state.", "properties": { "analytics_write_mode": { "$ref": "#/components/schemas/CloudAnalyticsWriteMode", "description": "ADR-043 §1: the independent analytics write mode (metrics under Phase\nC1). Orthogonal to `write_mode` — a project may be Cloud-primary for\nspans and local for analytics, or vice versa." }, "attribute_allowlist": { "items": { "type": "string" }, "type": "array" }, "cloud_write_mode_available": { "description": "Whether `write_mode = cloud` could be set right now.\n\n`false` is the normal state on an unlinked instance and must render as\nonboarding, not as an error.", "type": "boolean" }, "dead_lettered_spans": { "description": "Spans this instance accepted for this project and gave up on delivering.\n\nThe instance-wide card only shows a count; this route is already scoped\nto one project, so it can say *why* without exposing another tenant's\nfailures.", "format": "int64", "type": "integer" }, "delivery_failing": { "description": "Whether delivery to Temps Cloud is failing for this project *now*:\nspans that already failed an attempt are still being retried.\n\nThis, not `dead_lettered_spans`, is what decides whether the console\nshows an alert. Dead letters are a permanent record of a past loss and\nstay non-zero after the instance recovers; an alert driven by them tells\na healthy instance it is broken, forever.", "type": "boolean" }, "delivery_failing_since": { "description": "When the oldest span still being retried reached this instance.", "format": "date-time", "type": [ "string", "null" ] }, "delivery_failure_action": { "description": "What the operator has to do to end the failure, when it is something\nthey can fix — today, re-enrolling after Cloud rejected the credential.", "type": [ "string", "null" ] }, "delivery_failure_error": { "description": "Why the most recent attempt failed, while `delivery_failing`.", "type": [ "string", "null" ] }, "delivery_failure_setup_path": { "type": [ "string", "null" ] }, "delivery_gaps": { "description": "Past stretches of span time that were never delivered, newest first.\nRendered as history, not as an alert.", "items": { "$ref": "#/components/schemas/CloudDeliveryGapResponse" }, "type": "array" }, "delivery_gaps_truncated": { "description": "Whether older delivery gaps exist beyond the ones listed. Their spans\nare still counted in `dead_lettered_spans`, so a client can say how many\nolder undelivered spans the list leaves out rather than presenting it as\ncomplete.", "type": "boolean" }, "effective_reason": { "oneOf": [ { "$ref": "#/components/schemas/TelemetryWriteIntervalReason", "description": "Why they differ. Absent when intent and reality agree." }, { "type": "null" } ] }, "effective_reason_message": { "type": [ "string", "null" ] }, "effective_write_mode": { "$ref": "#/components/schemas/CloudTelemetryWriteMode", "description": "Where this project's spans are going right now, which differs from\n`write_mode` during a quota or credential fallback." }, "fidelity": { "$ref": "#/components/schemas/CloudTelemetryFidelity" }, "gap_windows": { "description": "Gap windows in the last 30 days.", "items": { "$ref": "#/components/schemas/TelemetryGapWindowResponse" }, "type": "array" }, "intervals": { "description": "The write-mode ledger, newest first.", "items": { "$ref": "#/components/schemas/TelemetryWriteIntervalResponse" }, "type": "array" }, "last_dead_letter_at": { "format": "date-time", "type": [ "string", "null" ] }, "last_dead_letter_error": { "description": "The reason the most recent give-up gave, if there is one.\n\nDelivery metadata only — this instance's own bounded error string. It is\nnever the span payload, and this field must not become a place one\nappears.", "type": [ "string", "null" ] }, "project_id": { "format": "int32", "type": "integer" }, "queued_spans": { "description": "Spans queued for Cloud for this project and not yet acknowledged.", "format": "int64", "type": "integer" }, "reason": { "description": "The single most relevant missing prerequisite, when\n`cloud_write_mode_available` is false.", "type": [ "string", "null" ] }, "retrying_spans": { "description": "Spans that failed at least one attempt and are still being retried.", "format": "int64", "type": "integer" }, "setup_path": { "type": [ "string", "null" ] }, "write_mode": { "$ref": "#/components/schemas/CloudTelemetryWriteMode", "description": "The operator's declared intent." } }, "required": [ "project_id", "fidelity", "attribute_allowlist", "write_mode", "effective_write_mode", "analytics_write_mode", "cloud_write_mode_available", "queued_spans", "dead_lettered_spans", "delivery_failing", "retrying_spans", "delivery_gaps", "delivery_gaps_truncated", "gap_windows", "intervals" ], "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" }, "ProjectDeliverySettingsResponse": { "properties": { "default_profile_id": { "format": "int32", "type": [ "integer", "null" ] }, "effective_default_profile": { "oneOf": [ { "$ref": "#/components/schemas/DeliveryProfileResponse" }, { "type": "null" } ] }, "environment_overrides": { "items": { "$ref": "#/components/schemas/EnvironmentDeliveryOverride" }, "type": "array" }, "project_id": { "format": "int32", "type": "integer" } }, "required": [ "project_id", "environment_overrides" ], "type": "object" }, "ProjectEnvVarInput": { "description": "Documentation-only schema for a project-creation environment variable.\n\nThe wire format is deserialized by [`CreateProjectEnvVar`], which also\naccepts the legacy `[\"KEY\", \"value\"]` tuple form. This struct exists so the\nOpenAPI spec (and the generated clients) describe the preferred object form\nwith its `is_secret` flag.", "properties": { "is_secret": { "description": "Mark the variable as a secret. Secret values are encrypted at rest,\nmasked in list responses, and revealable only through an audited,\npermission-checked endpoint. Defaults to `false`.", "type": "boolean" }, "key": { "description": "Variable name, e.g. `DATABASE_URL`", "type": "string" }, "value": { "description": "Variable value", "type": "string" } }, "required": [ "key", "value" ], "type": "object" }, "ProjectHealthSummary": { "description": "Health summary for a single project over the requested time range.", "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" }, "hourly_requests": { "description": "Hourly request counts ordered by bucket start.", "items": { "$ref": "#/components/schemas/ProjectHourlyRequestCount" }, "type": "array" }, "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", "hourly_requests" ], "type": "object" }, "ProjectHourlyRequestCount": { "description": "One hourly request-count point in a project health summary.", "properties": { "bucket": { "description": "Start of the UTC hour in RFC 3339 format.", "example": "2026-08-16T12:00:00Z", "type": "string" }, "request_count": { "format": "int64", "type": "integer" } }, "required": [ "bucket", "request_count" ], "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\", \"not_deployed\"\n(monitors exist but the environment has no deployment to check yet),\nor \"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" ] }, "dockerfilePath": { "description": "Repository-root-relative path to the Dockerfile, when it does not\nlive directly under `{path}/Dockerfile` (e.g. `docker/Dockerfile`\nrolled up to a `path` of `\"./\"`). `None` for a Dockerfile located\ndirectly at `{path}/Dockerfile` and for every non-Dockerfile preset.", "type": [ "string", "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_api_traffic_summary_enabled": { "description": "Opt-in to AI summarization of API traffic analytics (NULL/false = off).", "type": [ "boolean", "null" ] }, "allow_alternate_sources": { "description": "Whether this project also accepts deployments from a source other than\n`source_type` — chiefly, whether a Git-backed project will take an\nuploaded source archive (`drop`). `null` or `false` means only the\nconfigured `source_type` (plus Docker images and static bundles, which\nevery project accepts) may be deployed.", "example": false, "type": [ "boolean", "null" ] }, "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" }, "docker_socket": { "oneOf": [ { "$ref": "#/components/schemas/DockerSocketCapability", "description": "Where this project is granted host Docker access (ADR 045), and what to\nset when it is granted nowhere.\n\nPopulated only on the single-project detail responses — computing it\ncosts a `nodes` query, and the list endpoints must stay cheap. `None`\ntherefore means \"not computed on this response\", never \"not granted\";\nclients read `granted` from the object, not from its presence." }, { "type": "null" } ] }, "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_provider_type": { "description": "Git provider behind `git_provider_connection_id`: `github`,\n`github_app`, `gitlab`, `gitea`, `bitbucket` or `generic`. `null` when\nthe project has no connection (public repository, Docker image or\nuploaded source).\n\nClients must use this rather than guessing the host from `git_url`: a\nself-hosted GitLab/Gitea/Bitbucket instance can live on any domain, and\na connected project may have no clone URL stored at all.", "example": "gitlab", "type": [ "string", "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" }, "image_retention_hours": { "description": "Hours to retain built Docker images before nightly cleanup. Null = use the\nsystem-wide default from settings.", "format": "int32", "type": [ "integer", "null" ] }, "is_public_repo": { "description": "Authoritative repository visibility. A missing connection alone does\nnot imply that an incompletely configured repository is public.", "type": "boolean" }, "last_deployment": { "format": "int64", "type": [ "integer", "null" ] }, "main_branch": { "type": "string" }, "name": { "type": "string" }, "preset": { "type": [ "string", "null" ] }, "preset_config": { "oneOf": [ { "$ref": "#/components/schemas/PresetConfigSchema", "description": "Preset-specific configuration (Dockerfile path, build context, etc.)" }, { "type": "null" } ] }, "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" }, "project_type": { "description": "Product lifecycle classification. `service` projects are tied to a\npersisted, versioned template release; this is independent from the\ndeployment transport in `source_type`.", "type": "string" }, "pull_only_root_directory": { "description": "When true, deploy clones only `directory` via git sparse-checkout.", "type": "boolean" }, "repo_name": { "type": [ "string", "null" ] }, "repo_owner": { "type": [ "string", "null" ] }, "service_template_image_url": { "description": "Logo from the immutable service-template release applied to this\nproject. Clients should prefer it over a deployed site's favicon.", "type": [ "string", "null" ] }, "service_template_version": { "description": "Exact service-template version currently applied to the project.", "type": [ "string", "null" ] }, "slug": { "type": "string" }, "source_type": { "$ref": "#/components/schemas/SourceType", "description": "Source type for deployments (git, docker_image, or static_files)" }, "template_slug": { "description": "Bundled template slug that created this project. Clients use this to\npresent template-specific runtime configuration instead of generic\nsource-build controls.", "type": [ "string", "null" ] }, "updated_at": { "format": "int64", "type": "integer" }, "vulnerability_scanning_enabled": { "description": "Opt-in Trivy vulnerability scanning of this project's deployed Docker\nimages. Off by default — project owners explicitly enable it.", "type": "boolean" } }, "required": [ "id", "slug", "name", "directory", "pull_only_root_directory", "main_branch", "project_type", "created_at", "updated_at", "is_public_repo", "deployment_config", "attack_mode", "error_source_context_enabled", "vulnerability_scanning_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": { "compose_services": { "description": "Compose services this secret is restricted to. Empty means every\nservice in the stack.", "items": { "type": "string" }, "type": "array" }, "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", "compose_services" ], "type": "object" }, "ProjectServiceInfo": { "properties": { "custom_database_name": { "type": [ "string", "null" ] }, "database_provisioning_mode": { "$ref": "#/components/schemas/DatabaseProvisioningMode" }, "id": { "format": "int32", "type": "integer" }, "project": { "$ref": "#/components/schemas/ProjectInfo" }, "service": { "$ref": "#/components/schemas/ExternalServiceInfo" } }, "required": [ "id", "project", "service", "database_provisioning_mode" ], "type": "object" }, "ProjectStatisticsResponse": { "properties": { "has_completed_deployment": { "description": "Whether an accessible project's deployment has reached the ready state.", "type": "boolean" }, "total_count": { "format": "int64", "type": "integer" } }, "required": [ "total_count", "has_completed_deployment" ], "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" }, "ProjectTemplate": { "description": "A curated project template", "properties": { "command": { "description": "Optional command passed to the container image. This is needed for\nproduction images whose default command is intentionally a development\nmode (for example Keycloak).", "items": { "type": "string" }, "type": [ "array", "null" ] }, "description": { "description": "Short description", "type": [ "string", "null" ] }, "env_vars": { "description": "Environment variables template", "items": { "$ref": "#/components/schemas/EnvVarTemplate" }, "type": "array" }, "exposed_port": { "description": "Container port the prebuilt image listens on (used for routing when\ndeploying from `image`). Falls back to the image's EXPOSE / 3000 default.", "format": "int32", "type": [ "integer", "null" ] }, "features": { "description": "Feature highlights", "items": { "type": "string" }, "type": "array" }, "git": { "$ref": "#/components/schemas/GitRef", "description": "Git repository reference (supports any git provider). Always present as\nthe source-of-truth / build fallback, even for image-based templates." }, "health_check_path": { "description": "HTTP health-check path probed after the container starts (image deploys\ncan't read `.temps.yaml`). Must start with '/'. Defaults to \"/\".", "type": [ "string", "null" ] }, "image": { "description": "Prebuilt Docker image reference (e.g. \"ghcr.io/org/app:latest\"). When set,\nthe one-click deploy pulls and runs this image directly (source_type\ndocker_image) instead of building from `git` — instant, no BuildKit. When\nabsent, the template builds from source.", "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" }, "is_public": { "description": "Whether the template is publicly visible", "type": "boolean" }, "kind": { "$ref": "#/components/schemas/TemplateKind", "description": "Gallery this template belongs to. Older configurations default to a\nsource-code starter, preserving their existing behaviour." }, "managed_service_bindings": { "additionalProperties": { "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" }, "type": "object" }, "description": "Environment aliases populated from a linked managed service. The outer\nkey is the Temps service type and each inner entry maps an application\nvariable to a variable supplied by that service.\n\nExample: `postgres.KC_DB_USERNAME: POSTGRES_USER`.", "propertyNames": { "type": "string" }, "type": "object" }, "name": { "description": "Display name", "type": "string" }, "preset": { "description": "Framework/preset to use (e.g., \"nextjs\", \"fastapi\", \"dockerfile\")", "type": "string" }, "preset_config": { "description": "Preset-specific configuration" }, "resources": { "oneOf": [ { "$ref": "#/components/schemas/TemplateResources", "description": "Minimum/safe runtime resources for this application. These values are\nvalidated against operator-configured tenant ceilings before creation." }, { "type": "null" } ] }, "screenshot_url": { "description": "URL to a full screenshot/banner preview of the deployed template (e.g.\n`/templates/nextjs-saas-starter.png`). Rendered as a wide preview on the\ntemplate card; optional — templates without one show no banner.", "type": [ "string", "null" ] }, "services": { "description": "Required external services (e.g., [\"postgres\", \"redis\"])", "items": { "type": "string" }, "type": "array" }, "slug": { "description": "Unique identifier for the template (used in URLs)", "type": "string" }, "sort_order": { "description": "Sort order for display (lower = first)", "format": "int32", "type": "integer" }, "tags": { "description": "Tags/categories for filtering", "items": { "type": "string" }, "type": "array" }, "version": { "description": "Version of this template release. Service projects pin this value and\nthe complete resolved definition so catalog updates are always an\nexplicit, reviewable upgrade rather than a silent runtime mutation.", "type": "string" } }, "required": [ "slug", "name", "git", "preset" ], "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" }, "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", "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" }, "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", "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" }, "credential_verification_status": { "description": "`verified`, `unverified`, or `not_saved`; never implies model access.", "type": "string" }, "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" ] }, "default_permission_mode_id": { "type": "string" }, "default_runtime_model_id": { "description": "Explicit default used when a new harness thread is created.", "type": [ "string", "null" ] }, "host_auth_hint": { "description": "Explains why `host_authenticated` is false (not installed vs.\ninstalled-but-not-authenticated), or `None` when it's true.", "type": [ "string", "null" ] }, "host_auth_method": { "description": "Authentication mechanism reported by the CLI running in the Temps\nprocess environment (for example `chatgpt_subscription` or\n`host_auth_store`). Never contains credential material.", "type": [ "string", "null" ] }, "host_authenticated": { "description": "True when the CLI is installed AND authenticated on **this host** —\nthe machine running the Temps server process. This is a completely\ndifferent signal from `credential_saved`: that field is about a\ncredential available to the server-side, turn-scoped workspace relay.\nPersistent workspace chat never inherits the host's ambient CLI\nsession. A provider can show\n`credential_saved: true` and `host_authenticated: false` at the same\ntime.", "type": "boolean" }, "host_version": { "description": "Installed CLI version used as part of the model-cache identity.", "type": [ "string", "null" ] }, "id": { "type": "string" }, "install_command": { "type": "string" }, "local_credential": { "oneOf": [ { "$ref": "#/components/schemas/LocalCredentialDto", "description": "Importable credential already used by this host's CLI, if one can be\ncopied directly into encrypted Temps settings. Contains metadata only." }, { "type": "null" } ] }, "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" ] }, "model_source": { "$ref": "#/components/schemas/ModelCatalogSource", "description": "Whether the catalog is live, cached, stale, or a bootstrap fallback." }, "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" }, "models_refreshed_at": { "description": "Time of the last successful account-aware CLI model discovery.", "type": [ "string", "null" ] }, "name": { "type": "string" }, "permission_modes": { "description": "Provider-native permission modes available to sandboxed harness turns.", "items": { "$ref": "#/components/schemas/SelectOption" }, "type": "array" }, "runtime_models": { "description": "Full normalized runtime capabilities used by application chat. Unlike\n`models`, this preserves resolved display names and reasoning choices.", "items": { "$ref": "#/components/schemas/ModelCapability" }, "type": "array" }, "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" }, "verification_hint": { "type": [ "string", "null" ] }, "workspace_readiness_hint": { "description": "Actionable explanation when `workspace_ready` is false.", "type": [ "string", "null" ] }, "workspace_ready": { "description": "True only when this provider can execute inside a persistent Temps\nworkspace with a saved credential and a secure turn-scoped relay.\nThis is the authoritative signal for workspace harness pickers.", "type": "boolean" } }, "required": [ "id", "name", "install_command", "auth_command", "auth_flavors", "models", "runtime_models", "permission_modes", "default_permission_mode_id", "credential_saved", "credential_verification_status", "supports_max_turns", "host_authenticated", "model_source", "workspace_ready" ], "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" }, "ProviderDetailResponse": { "properties": { "key": { "$ref": "#/components/schemas/ProviderKeyResponse" }, "models": { "items": { "$ref": "#/components/schemas/ProviderModelResponse" }, "type": "array" } }, "required": [ "key", "models" ], "type": "object" }, "ProviderDomainIdentityResponse": { "description": "A single domain identity already registered on the provider's side,\noffered for import.", "properties": { "domain": { "example": "example.com", "type": "string" }, "provider_identity_id": { "example": "12345678-1234-1234-1234-123456789012", "type": "string" }, "status": { "description": "The provider's current verification status for this domain\n(\"verified\", \"pending\", \"failed\", \"not_started\", \"temporary_failure\")", "example": "verified", "type": "string" } }, "required": [ "domain", "provider_identity_id", "status" ], "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" }, "ProviderModelResponse": { "properties": { "display_name": { "type": "string" }, "id": { "format": "int32", "type": "integer" }, "is_available": { "type": "boolean" }, "is_enabled": { "type": "boolean" }, "last_seen_at": { "type": [ "string", "null" ] }, "model_id": { "type": "string" }, "owned_by": { "type": [ "string", "null" ] }, "provider_key_id": { "format": "int32", "type": "integer" }, "source": { "type": "string" }, "updated_at": { "type": "string" } }, "required": [ "id", "provider_key_id", "model_id", "display_name", "source", "is_available", "is_enabled", "updated_at" ], "type": "object" }, "ProviderPreset": { "properties": { "automatic": { "description": "Whether a value-pattern match can safely identify the public issuer.", "type": "boolean" }, "description": { "type": "string" }, "documentation_url": { "type": "string" }, "id": { "type": "string" }, "name": { "type": "string" }, "spec": { "$ref": "#/components/schemas/HttpCheckSpec" } }, "required": [ "id", "name", "description", "spec", "automatic", "documentation_url" ], "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" } ] } ] }, "ProxyLogAccessResponse": { "properties": { "allowed": { "type": "boolean" }, "reason": { "type": [ "string", "null" ] } }, "required": [ "allowed" ], "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_headers": { "additionalProperties": { "type": "string" }, "description": "Inbound request headers, credential values already replaced with\n`[REDACTED]` at ingest (see [`crate::redaction`]). `None` when the entry\npredates header capture or was written by a path that doesn't record\nthem; an empty map means \"captured, but no headers\", which is different\nand worth being able to tell apart.\n\nA `BTreeMap` rather than a raw `serde_json::Value` so the schema stays\ntyped and the UI gets a stable alphabetical ordering for free.", "propertyNames": { "type": "string" }, "type": [ "object", "null" ] }, "request_id": { "type": "string" }, "request_size_bytes": { "format": "int64", "type": [ "integer", "null" ] }, "request_source": { "type": "string" }, "response_headers": { "additionalProperties": { "type": "string" }, "description": "Upstream response headers, redacted on the same terms as\n[`Self::request_headers`].", "propertyNames": { "type": "string" }, "type": [ "object", "null" ] }, "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" }, "PublicComposePreviewRequest": { "properties": { "branch": { "type": [ "string", "null" ] }, "composeOverride": { "type": [ "string", "null" ] }, "excludedServices": { "items": { "type": "string" }, "type": "array" }, "path": { "type": "string" }, "previewPolicy": { "$ref": "#/components/schemas/ComposeSecurityPolicy", "description": "Advisory preview only. Deployment reloads the saved project policy." } }, "required": [ "path" ], "type": "object" }, "PublicComposePreviewResponse": { "properties": { "branch": { "type": "string" }, "disabledServices": { "items": { "type": "string" }, "type": "array" }, "effectiveCompose": { "description": "Effective user-controlled Compose YAML with sensitive values redacted.", "type": "string" }, "enabledServices": { "items": { "type": "string" }, "type": "array" }, "path": { "type": "string" }, "redactedValues": { "minimum": 0, "type": "integer" } }, "required": [ "branch", "path", "effectiveCompose", "enabledServices", "disabledServices", "redactedValues" ], "type": "object" }, "PublicComposeServicePreview": { "description": "A single service parsed from a compose file's `services:` map", "properties": { "depends_on": { "items": { "type": "string" }, "type": "array" }, "detected_service_type": { "oneOf": [ { "$ref": "#/components/schemas/ComposeServiceFamily", "description": "Well-known managed-service family detected from the image, if any." }, { "type": "null" } ] }, "environment_variables": { "description": "Environment variable names declared by this service. Values are\nintentionally omitted.", "items": { "type": "string" }, "type": "array" }, "health_check_path": { "description": "HTTP path declared by a loopback Compose healthcheck, if unambiguous.", "type": [ "string", "null" ] }, "image": { "type": [ "string", "null" ] }, "looks_like_database": { "description": "True when the image looks like a well-known database engine\n(Postgres/MySQL/MariaDB/MongoDB/Redis and common forks) — a raw\ncompose service never becomes a Temps-managed `external_services` row,\nso it never gets backup/restore. Informational only.", "type": "boolean" }, "name": { "type": "string" }, "ports": { "description": "Ports declared by Compose. `target` is the container port Temps can\nroute to; `published` is only the optional Docker host port.", "items": { "$ref": "#/components/schemas/ComposePortMapping" }, "type": "array" } }, "required": [ "name", "depends_on", "environment_variables", "looks_like_database", "ports" ], "type": "object" }, "PublicComposeServicesResponse": { "description": "Response for compose-file service preview", "properties": { "branch": { "description": "Branch the file was read from", "type": "string" }, "path": { "type": "string" }, "services": { "items": { "$ref": "#/components/schemas/PublicComposeServicePreview" }, "type": "array" } }, "required": [ "branch", "path", "services" ], "type": "object" }, "PublicEnvExampleResponse": { "description": "Response for env-example detection", "properties": { "branch": { "description": "Branch the file was read from", "type": "string" }, "path": { "description": "Path of the detected env-example file (e.g. \".env.example\"), `null`\nif the repository has none", "type": [ "string", "null" ] }, "variables": { "description": "Parsed variables (empty if no env-example file was found)", "items": { "$ref": "#/components/schemas/EnvExampleVariable" }, "type": "array" } }, "required": [ "branch", "variables" ], "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" }, "PublicIngressHeartbeat": { "properties": { "certificate_count": { "format": "int64", "type": "integer" }, "last_error": { "type": [ "string", "null" ] }, "route_count": { "format": "int64", "type": "integer" }, "running": { "type": "boolean" }, "unsupported_reasons": { "items": { "type": "string" }, "type": "array" }, "unsupported_route_count": { "format": "int64", "type": "integer" } }, "required": [ "running", "certificate_count", "route_count", "unsupported_route_count" ], "type": "object" }, "PublicIpInfo": { "description": "Information about a public IP address lookup", "properties": { "error": { "description": "Error message if IP lookup failed", "type": [ "string", "null" ] }, "ip": { "description": "The public IP address, if successfully retrieved", "type": [ "string", "null" ] }, "source": { "description": "The source service that provided the IP", "type": [ "string", "null" ] } }, "type": "object" }, "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\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" } }, "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" }, "ReassignCustomDomainRequest": { "properties": { "target_environment_id": { "format": "int32", "type": "integer" }, "target_project_id": { "format": "int32", "type": "integer" } }, "required": [ "target_project_id", "target_environment_id" ], "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" }, "RecordOwnershipResponse": { "description": "Ownership state of one record, for the conflict/import UI", "properties": { "environment_id": { "description": "Environment stamped in the ownership marker, when owned", "format": "int32", "type": [ "integer", "null" ] }, "owner_instance": { "description": "Owning install's instance ID when owned by a different temps install", "type": [ "string", "null" ] }, "project_id": { "description": "Project stamped in the ownership marker, when owned", "format": "int32", "type": [ "integer", "null" ] }, "record": { "oneOf": [ { "$ref": "#/components/schemas/DnsRecord", "description": "The record at the provider, when one exists" }, { "type": "null" } ] }, "status": { "description": "One of: not_found | unmanaged | owned | owned_by_other | orphaned |\nblocked_by_other | registry_conflict", "example": "unmanaged", "type": "string" }, "writable": { "description": "Whether this temps install may modify the record", "type": "boolean" } }, "required": [ "status", "writable" ], "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" }, "RefreshProviderModelsResponse": { "properties": { "default_runtime_model_id": { "type": [ "string", "null" ] }, "model_source": { "$ref": "#/components/schemas/ModelCatalogSource" }, "models_refreshed_at": { "type": [ "string", "null" ] }, "provider_id": { "type": "string" }, "runtime_models": { "items": { "$ref": "#/components/schemas/ModelCapability" }, "type": "array" } }, "required": [ "provider_id", "runtime_models", "model_source" ], "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" }, "mtls_required": { "description": "Whether this node must serve mTLS and reject plaintext agent traffic.", "type": "boolean" }, "name": { "type": "string" }, "status": { "type": "string" } }, "required": [ "id", "name", "status", "message", "mtls_required" ], "type": "object" }, "RegisterRequest": { "properties": { "email": { "type": "string" }, "name": { "type": "string" }, "password": { "type": "string" } }, "required": [ "email", "password", "name" ], "type": "object" }, "RegisterWireguardMeshRequest": { "description": "Body of `PUT /internal/nodes/{node_id}/network/wireguard`.", "properties": { "endpoint": { "description": "`ip:port` other nodes dial to reach this node's WireGuard socket.", "type": "string" }, "public_key": { "description": "Base64 WireGuard public key. The private key never leaves the node.", "type": "string" } }, "required": [ "public_key", "endpoint" ], "type": "object" }, "RegisterWireguardMeshResponse": { "description": "Response of `PUT /internal/nodes/{node_id}/network/wireguard`.", "properties": { "address": { "description": "Mesh address assigned to this node; also its overlay underlay.", "type": "string" }, "listen_port": { "format": "int32", "minimum": 0, "type": "integer" }, "prefix_len": { "format": "int32", "minimum": 0, "type": "integer" } }, "required": [ "address", "prefix_len", "listen_port" ], "type": "object" }, "RegistryEnvelope": { "description": "The outer envelope signs the decoded bytes in `payload`. Encoding the\npayload instead of reserializing a JSON object avoids ambiguous map order,\nwhitespace, and number representations.", "properties": { "key_id": { "type": "string" }, "payload": { "description": "Standard-base64 encoded JSON [`RegistryDocument`].", "type": "string" }, "signature": { "description": "Standard-base64 encoded 64-byte Ed25519 signature over payload bytes.", "type": "string" } }, "required": [ "key_id", "payload", "signature" ], "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" }, "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": { "items": { "type": "string" }, "type": "array" } }, "required": [ "releases" ], "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" }, "RenewalAttemptResponse": { "description": "One row of the standard (non-on-demand) renewal-attempt audit log, backing\nthe domain detail page's renewal timeline.", "properties": { "created_at": { "description": "When the attempt was recorded (epoch millis).", "format": "int64", "type": "integer" }, "error": { "type": [ "string", "null" ] }, "error_type": { "type": [ "string", "null" ] }, "id": { "format": "int32", "type": "integer" }, "outcome": { "description": "`\"success\"` | `\"failed\"`.", "type": "string" }, "stage": { "description": "`\"request_challenge\"` | `\"complete_challenge\"`.", "type": "string" }, "verification_method": { "description": "`\"http-01\"` | `\"dns-01\"`.", "type": "string" } }, "required": [ "id", "stage", "verification_method", "outcome", "created_at" ], "type": "object" }, "RepointContinuousArchiveSourceRequest": { "description": "Deliberately, explicitly move where a service's continuous archiving\nprocess (Postgres/Timescale WAL-G, MariaDB's binlog shipper) points. See\n`ExternalServiceManager::repoint_continuous_archive_source` for why this is a\ndedicated, guarded operation rather than something a schedule change\ndoes implicitly.", "properties": { "new_s3_source_id": { "description": "The S3 source continuous archiving should point at from now on.", "format": "int32", "type": "integer" } }, "required": [ "new_s3_source_id" ], "type": "object" }, "ReportWireguardHandshakesRequest": { "description": "Body of `PUT /internal/nodes/{node_id}/network/wireguard/handshakes`: when\nthis node last completed a WireGuard handshake with each peer. Peers it\nnever handshook with are left out.", "properties": { "peers": { "items": { "$ref": "#/components/schemas/WireguardHandshakeReport" }, "type": "array" } }, "required": [ "peers" ], "type": "object" }, "RepositoryComposeServicesResponse": { "properties": { "path": { "type": "string" }, "repositoryId": { "format": "int32", "type": "integer" }, "services": { "items": { "$ref": "#/components/schemas/ComposeServicePreviewResponse" }, "type": "array" } }, "required": [ "repositoryId", "path", "services" ], "type": "object" }, "RepositoryEnvExampleResponse": { "properties": { "path": { "description": "Path of the detected env-example file (e.g. \".env.example\"), `null`\nif the repository has none", "type": [ "string", "null" ] }, "repositoryId": { "format": "int32", "type": "integer" }, "variables": { "items": { "$ref": "#/components/schemas/EnvExampleVariableResponse" }, "type": "array" } }, "required": [ "repositoryId", "variables" ], "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" ] }, "preset": { "description": "Cached default-branch preset slug, or __undetected__ for uninspected repositories.", "type": [ "string", "null" ] }, "private": { "type": [ "boolean", "null" ] }, "search": { "type": [ "string", "null" ] }, "sort": { "type": [ "string", "null" ] }, "updated_after": { "format": "date-time", "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" }, "RequestDiscoveredRouteCertRequest": { "description": "Request body for Path A: operator-triggered ACME issuance.", "properties": { "acknowledge_manual_dns_renewal": { "description": "Must be `true` when `challenge_type` is `\"dns-01\"` and no verified\n`auto_manage` zone covers this host. Lets the operator confirm they\nknow renewal will require manual DNS updates.", "type": "boolean" }, "challenge_type": { "description": "`\"http-01\"` or `\"dns-01\"`. Required — no silent default.", "type": "string" } }, "required": [ "challenge_type" ], "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" }, "RequestTimeoutSettings": { "description": "Upstream request/connection timeouts for customer app traffic.\n\nBy default, no timeout is applied to customer app traffic at all — an\nexisting app that happens to have a slow endpoint, a long-polling\nrequest, or an unusually long response must keep working exactly as it\ndid before this setting existed. Timeouts here are opt-in: an operator\ncan set a global default, and/or a project/environment can set its own\noverride (`DeploymentConfig::request_timeout_seconds` /\n`sse_idle_timeout_seconds` / `websocket_idle_timeout_seconds`), but until\none of those is explicitly configured, the proxy holds the connection\nopen indefinitely (bounded only by TCP/OS-level limits).\n\n`default_*_timeout_seconds` of `0` means \"no timeout\" — this is the\nout-of-the-box value for all three. `max_request_timeout_seconds` is a\nhard ceiling that only comes into play once a timeout is actually\nconfigured (globally or per project/environment): whatever value is\nresolved is always clamped to it, so lowering the ceiling here takes\neffect immediately without needing every environment row re-saved. It\nnever *creates* a timeout for traffic that has none.", "properties": { "default_http_timeout_seconds": { "default": 0, "description": "Default timeout for regular (non-streaming) HTTP requests, in\nseconds. Used when a project/environment hasn't set\n`request_timeout_seconds`. `0` (the default) means no timeout.", "example": 0, "format": "int32", "minimum": 0, "type": "integer" }, "default_sse_idle_timeout_seconds": { "default": 0, "description": "Default idle timeout for Server-Sent Events streams, in seconds. Used\nwhen a project/environment hasn't set `sse_idle_timeout_seconds`. `0`\n(the default) means no timeout.", "example": 0, "format": "int32", "minimum": 0, "type": "integer" }, "default_websocket_idle_timeout_seconds": { "default": 0, "description": "Default idle timeout for WebSocket connections, in seconds. Used when\na project/environment hasn't set `websocket_idle_timeout_seconds`.\n`0` (the default) means no timeout.", "example": 0, "format": "int32", "minimum": 0, "type": "integer" }, "max_request_timeout_seconds": { "default": 600, "description": "Hard ceiling, in seconds, applied once a timeout is configured (via a\nglobal default above or a project/environment override). Has no\neffect on traffic with no timeout configured at all.", "example": 600, "format": "int32", "maximum": 86400, "minimum": 5, "type": "integer" } }, "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": [ { "$ref": "#/components/schemas/MfaSetupResponse" }, { "type": "null" } ] }, "success": { "type": "boolean" }, "user_id": { "format": "int32", "type": "integer" } }, "required": [ "success", "message", "user_id", "mfa_enrollment_required" ], "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" }, "ResetUserPasswordResponse": { "description": "Returned once when an administrator resets another user's password. The\ntemporary password is not stored in retrievable form, so this response is\nthe only place it ever appears. The user must replace it at next sign-in.", "properties": { "must_change_password": { "description": "Always true: the user must choose a new password at next sign-in.", "type": "boolean" }, "temporary_password": { "example": "Kp7#mW2qRz9!vN4xT8b$", "type": "string" } }, "required": [ "temporary_password", "must_change_password" ], "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" }, "ResolvePermissionRequest": { "description": "Body for the `POST .../permissions/{permission_id}/resolve` endpoint.", "properties": { "decision": { "$ref": "#/components/schemas/PermissionDecision" } }, "required": [ "decision" ], "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. Regular manual values and integration values can be fetched per-key\nthrough an audited endpoint; marked secret manual values are write-only.", "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": [ { "$ref": "#/components/schemas/EnvVarIntegrationInfo" }, { "type": "null" } ] }, "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" }, "ResponseField": { "oneOf": [ { "properties": { "kind": { "enum": [ "header" ], "type": "string" }, "value": { "type": "string" } }, "required": [ "value", "kind" ], "type": "object" }, { "properties": { "kind": { "enum": [ "json_pointer" ], "type": "string" }, "value": { "type": "string" } }, "required": [ "value", "kind" ], "type": "object" } ] }, "ResponseObject": { "allOf": [ { "description": "`output`, `error`, `incomplete_details` and every other field.", "type": "object" }, { "properties": { "id": { "type": "string" }, "model": { "type": "string" }, "object": { "description": "Always `response`", "type": "string" }, "status": { "description": "`completed`, `incomplete`, `failed`, `in_progress`, …", "type": [ "string", "null" ] }, "usage": { "oneOf": [ { "$ref": "#/components/schemas/ResponseUsage" }, { "type": "null" } ] } }, "required": [ "id", "object", "model" ], "type": "object" } ], "description": "A response object as returned by the provider." }, "ResponseStreamEvent": { "allOf": [ { "type": "object" }, { "properties": { "type": { "type": "string" } }, "required": [ "type" ], "type": "object" } ], "description": "One JSON payload in the Responses SSE stream. Event-specific fields are retained." }, "ResponseUsage": { "description": "Token usage of a response.", "properties": { "input_tokens": { "format": "int64", "type": "integer" }, "output_tokens": { "format": "int64", "type": "integer" }, "total_tokens": { "format": "int64", "type": "integer" } }, "type": "object" }, "ResponsesRequest": { "allOf": [ { "description": "Every other Responses API field (`input`, `instructions`, `tools`,\n`text`, `reasoning`, …), forwarded unchanged.", "type": "object" }, { "properties": { "background": { "description": "Run asynchronously and poll for the result. Requires your own\nprovider key: the result is fetched from the provider account.", "type": [ "boolean", "null" ] }, "conversation": { "description": "Attach the response to a stored conversation. Requires your own\nprovider key, for the same reason as `previous_response_id`.", "type": [ "object", "null" ] }, "model": { "description": "Model to run, e.g. `gpt-6-luna`. Must be served by OpenAI.", "type": "string" }, "previous_response_id": { "description": "Continue from a stored response. Requires your own provider key\n(`X-Provider-Api-Key`), because stored responses live in the\nprovider account that created them.", "type": [ "string", "null" ] }, "stream": { "description": "Stream the reply as server-sent events.", "type": "boolean" } }, "required": [ "model" ], "type": "object" } ], "description": "Request body of `POST /ai/v1/responses`, OpenAI's Responses API." }, "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": { "cross_service": { "description": "Whether the backup was produced by a service other than the target\n(or its origin is unknown). A destructive cross-service restore must\nbe confirmed explicitly with `confirm_cross_service: true`.", "type": "boolean" }, "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\",\n\"mariadb_physical_restore\", \"mariadb_dump_restore\", or \"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", "cross_service", "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 a backup that anchors a\ncontinuous change stream: a WAL-G base (Postgres) or a physical\n`mariadb-backup` base with archived binary logs (MariaDB).", "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" } ] }, "RestoreRunSourceBackup": { "description": "The backup a restore run reads.", "properties": { "backup_id": { "description": "The backup's UUID, which addresses it in the console and the\n`/backups/{id}` API. `None` for a raw-location restore, or when the\ntracked backup has since been deleted.", "type": [ "string", "null" ] }, "id": { "description": "`backups.id` of a tracked backup. `None` for a restore from a raw S3\nlocation (a backup this instance did not record).", "format": "int32", "type": [ "integer", "null" ] }, "location": { "description": "Object key or `s3://` URL of the backup.", "type": [ "string", "null" ] }, "s3_source_id": { "description": "S3 source holding the backup.", "format": "int32", "type": [ "integer", "null" ] }, "taken_at": { "description": "When the backup was taken (ISO 8601). `None` when unknown.", "type": [ "string", "null" ] } }, "type": "object" }, "RestoreRunView": { "properties": { "cancel_requested_at": { "description": "When cancellation was requested, if it was.", "type": [ "string", "null" ] }, "cancellable": { "description": "Whether `POST /restore-runs/{id}/cancel` would be accepted now.", "type": "boolean" }, "created_at": { "type": "string" }, "error_message": { "type": [ "string", "null" ] }, "finished_at": { "type": [ "string", "null" ] }, "id": { "format": "int32", "type": "integer" }, "mode": { "type": "string" }, "not_cancellable_reason": { "description": "Why the run cannot be cancelled now; `None` when `cancellable`.", "type": [ "string", "null" ] }, "phase": { "type": "string" }, "recovery_target": {}, "source_backup": { "$ref": "#/components/schemas/RestoreRunSourceBackup", "description": "The backup this run restores from, so a client can show and link to\nit. Always present; its fields are `None` where they are unknown." }, "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", "cancellable", "source_backup" ], "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" }, "RotateClusterCaRequest": { "properties": { "confirmation": { "description": "Destructive-action guard. Must be exactly `ROTATE CLUSTER CA`.", "type": "string" }, "expected_fingerprint": { "description": "Fingerprint observed through a trusted operator channel immediately\nbefore rotation. The request fails if the active root changed.", "type": "string" } }, "required": [ "expected_fingerprint", "confirmation" ], "type": "object" }, "RotateClusterCaResponse": { "properties": { "message": { "type": "string" }, "new_fingerprint": { "type": "string" }, "previous_fingerprint": { "type": "string" }, "revoked_enrollment_tokens": { "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "previous_fingerprint", "new_fingerprint", "revoked_enrollment_tokens", "message" ], "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" }, "RouteTestDelivery": { "properties": { "message": { "type": [ "string", "null" ] }, "provider_id": { "format": "int32", "type": "integer" }, "provider_name": { "type": "string" }, "provider_type": { "type": "string" }, "status": { "$ref": "#/components/schemas/RouteTestDeliveryStatus" } }, "required": [ "provider_id", "provider_name", "provider_type", "status" ], "type": "object" }, "RouteTestDeliveryStatus": { "description": "Outcome of sending a test notification to one provider of a route.", "enum": [ "sent", "failed", "skipped_disabled" ], "type": "string" }, "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" }, "must_change_password": { "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", "must_change_password", "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" }, "RuntimeCredentialsResponse": { "description": "Live connection variables for a service in one environment.\n\nEvery value is plaintext — this is the response of the audited issuance\nendpoint, not of the masked bulk read. Callers must treat it as a\ncredential: do not log it, do not cache it, do not put it in an error.", "properties": { "variables": { "additionalProperties": { "type": "string" }, "description": "Connection variables, e.g. `POSTGRES_URL`, `POSTGRES_PASSWORD`.", "propertyNames": { "type": "string" }, "type": "object" } }, "required": [ "variables" ], "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" }, "managed_by_cloud": { "description": "True when this source was auto-provisioned by a Temps Cloud link\nrather than entered by an operator. Managed sources cannot be edited\nor deleted from this API; disconnect Temps Cloud to remove one.", "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", "managed_by_cloud", "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" ] }, "lifecycle": { "description": "Lifecycle class (ADR-036): `\"ephemeral\"` or `\"workspace\"`. Always\npresent — a client that doesn't know about workspaces sees\n`\"ephemeral\"` and behaves exactly as before.", "type": "string" }, "memory": { "format": "int64", "minimum": 0, "type": "integer" }, "name": { "type": "string" }, "node_id": { "description": "Worker node hosting the sandbox (ADR-048). `null` = the control plane.", "format": "int32", "type": [ "integer", "null" ] }, "node_name": { "description": "Name of the hosting node; `\"control-plane\"` for control-plane\nsandboxes.", "type": "string" }, "preview_password_hint": { "type": [ "string", "null" ] }, "preview_url_template": { "type": "string" }, "project_id": { "description": "Project this sandbox was created from, when created from one.", "format": "int32", "type": [ "integer", "null" ] }, "region": { "type": "string" }, "requestedAt": { "description": "Creation time as Unix epoch milliseconds.", "format": "int64", "type": "integer" }, "runtime": { "type": "string" }, "source_repo_url": { "description": "Repo the work dir was seeded from. Never carries credentials.", "type": [ "string", "null" ] }, "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", "lifecycle", "node_name" ], "type": "object" }, "SandboxPlacementResponse": { "description": "Sandbox placement state: the operator allow-list and every node.", "properties": { "allowed_node_ids": { "description": "Node ids allowed to run sandboxes. `null` = every node (the default);\n`0` is the control plane.", "items": { "format": "int32", "type": "integer" }, "type": [ "array", "null" ] }, "nodes": { "description": "Every node (control plane first) with its placement state.", "items": { "$ref": "#/components/schemas/PlacementNode" }, "type": "array" } }, "required": [ "nodes" ], "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" }, "SandboxRuntimeEnvironmentResponse": { "description": "Live project runtime variables issued to a sandbox. Values are deliberately\nabsent from Debug output and must not be cached or persisted by Temps.", "properties": { "variables": { "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" }, "type": "object" } }, "required": [ "variables" ], "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" }, "verification_model": { "description": "OpenCode model to test, in `provider/model` form. Omit to use the\nbuilt-in minimal probe model. A successfully verified explicit model\nbecomes this provider's workspace default.", "type": [ "string", "null" ] } }, "required": [ "auth_type", "credential" ], "type": "object" }, "SaveCredentialResponse": { "properties": { "auth_type": { "type": "string" }, "credential_verification_status": { "type": "string" }, "provider": { "$ref": "#/components/schemas/ProviderCatalogDto" }, "provider_id": { "type": "string" }, "saved": { "type": "boolean" }, "verification_hint": { "type": [ "string", "null" ] } }, "required": [ "saved", "credential_verification_status", "provider_id", "auth_type", "provider" ], "type": "object" }, "SaveHttpCheck": { "description": "Credentials and recipe headers are write-only and encrypted at rest.\nA check reads at most one of `env_var_id`, `secret_id` and `credential`.", "properties": { "credential": { "type": [ "string", "null" ] }, "enabled": { "type": "boolean" }, "env_var_id": { "format": "int32", "type": [ "integer", "null" ] }, "interval_seconds": { "format": "int32", "type": "integer" }, "kind": { "$ref": "#/components/schemas/CheckKind", "description": "`http` (default) calls an endpoint; `local` reads expiring items\n(certificates, SSH certificates, OpenPGP keys, kubeconfigs, JWTs) on this host." }, "local": { "oneOf": [ { "$ref": "#/components/schemas/LocalCheckSpec", "description": "Expiry thresholds for `local` checks; defaults to 30, 7 and 1 days." }, { "type": "null" } ] }, "name": { "type": "string" }, "secret_id": { "description": "Project secret to check. HTTP checks may only send a secret to the\nprovider its value is recognized as; local checks never send it.", "format": "int32", "type": [ "integer", "null" ] }, "spec": { "oneOf": [ { "$ref": "#/components/schemas/HttpCheckSpec", "description": "HTTP recipe; required for `http` checks and rejected for `local` checks." }, { "type": "null" } ] } }, "required": [ "name" ], "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": { "description": "Opaque keyset cursor for the next (older) page. Stays populated on a\npartial page — that's the whole point: the user can press Next to keep\nsearching.", "type": [ "string", "null" ] }, "partial": { "description": "`true` when the store's time/byte budget ran out before this page\ncould be proven complete.", "type": "boolean" }, "scanned_back_to": { "description": "Set when `partial` is `true`: every chunk ending after this timestamp\nhas been searched, nothing older has yet.", "type": [ "string", "null" ] } }, "required": [ "lines" ], "type": "object" }, "Seasonality": { "description": "Seasonality model for an anomaly baseline.", "enum": [ "none", "hourly", "daily", "weekly" ], "type": "string" }, "SecretDetectionView": { "properties": { "candidates": { "items": { "$ref": "#/components/schemas/Candidate" }, "type": "array" }, "detection_rule_count": { "minimum": 0, "type": "integer" }, "local_artifacts": { "description": "Expiring items a local check would read. Labels and dates only, never\nvalues or token claims.", "items": { "$ref": "#/components/schemas/ExpiringArtifact" }, "type": "array" }, "secret_id": { "format": "int32", "type": "integer" } }, "required": [ "secret_id", "candidates", "local_artifacts", "detection_rule_count" ], "type": "object" }, "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": [ { "$ref": "#/components/schemas/ChallengeConfig", "description": "Challenge configuration (future: CAPTCHA, JS challenge, etc.)" }, { "type": "null" } ] }, "enabled": { "description": "Enable/disable security features at this level\nIf None, inherits from parent level", "type": [ "boolean", "null" ] }, "geoRestrictions": { "oneOf": [ { "$ref": "#/components/schemas/GeoRestrictionsConfig", "description": "Geographic restrictions (future: country blocking, etc.)" }, { "type": "null" } ] }, "headers": { "oneOf": [ { "$ref": "#/components/schemas/SecurityHeadersConfig", "description": "Security headers configuration" }, { "type": "null" } ] }, "passwordProtection": { "oneOf": [ { "$ref": "#/components/schemas/PasswordProtectionConfig", "description": "Password protection: shows an HTML password form before allowing access" }, { "type": "null" } ] }, "rateLimiting": { "oneOf": [ { "$ref": "#/components/schemas/RateLimitConfig", "description": "Rate limiting configuration" }, { "type": "null" } ] } }, "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" }, "SelectOption": { "properties": { "description": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ], "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" }, "migrations_applied": { "description": "Number of database migrations that were successfully applied during\nthis attempt. Set at completion (success or migration failure). `None`\nif migrations were never reached (pre-swap failure).", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "migrations_total": { "description": "Total number of database migrations that were planned. Set at the same\ntime as `migrations_applied`. `None` if migrations were never reached.", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "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", "migrating", "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": { "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" }, "SendFailureReportRequest": { "properties": { "report_text": { "description": "The report text as reviewed (and possibly edited) by the user.", "type": "string" } }, "required": [ "report_text" ], "type": "object" }, "SendMessageAcceptedResponse": { "description": "Acknowledgement that a durable, server-owned turn has started. Live token,\ntool, permission, error, and completion events are delivered exclusively by\nthe conversation WebSocket.", "properties": { "status": { "type": "string" }, "turn_id": { "type": "string" }, "turn_started_at": { "description": "Server timestamp used by every observer to render one continuous\nelapsed-time counter across refreshes and reconnects.", "type": "string" } }, "required": [ "turn_id", "status", "turn_started_at" ], "type": "object" }, "SendMessageRequest": { "properties": { "ai_model": { "description": "Optional next-turn model. The provider harness remains pinned, but its\nadvertised models may be changed between turns.", "type": [ "string", "null" ] }, "ai_permission_mode": { "description": "Optional next-turn permission mode for the pinned provider harness.", "type": [ "string", "null" ] }, "ai_thinking_level": { "description": "Optional next-turn thinking level.", "type": [ "string", "null" ] }, "attachments": { "description": "Opaque references returned by the conversation attachment endpoint.", "items": { "$ref": "#/components/schemas/ChatAttachmentReference" }, "type": "array" }, "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" ] }, "turn_id": { "description": "Client-generated opaque idempotency key for this turn. Retries with the\nsame id never create a second user message or harness execution.", "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" }, "node_id": { "description": "Node the rule is scoped to. `0` is the synthetic control-plane node\n(see `CONTROL_PLANE_NODE_ID`), which owns the `proxy.*` and `node.*`\nrules. Exactly one of `service_id`/`deployment_id`/`node_id` is set.", "format": "int32", "type": [ "integer", "null" ] }, "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" }, "ServicePublicUrl": { "description": "A public URL of a compose service and the container port it routes to.", "properties": { "port": { "description": "Container port this URL routes to.", "example": 3000, "format": "int32", "minimum": 0, "type": "integer" }, "service": { "description": "Compose service this URL routes to.", "example": "web", "type": "string" }, "url": { "example": "https://web--production.localho.st", "type": "string" } }, "required": [ "service", "port", "url" ], "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" }, "ServiceTemplateChangeKind": { "enum": [ "added", "removed", "changed" ], "type": "string" }, "ServiceTemplateInstance": { "description": "Immutable template release attached to a service project.\n\nThe resolved definition is deliberately stored with the project. The live\ncatalog is only needed to discover a newer release; deployments, edits and\nrollbacks continue to work if the catalog later changes or disappears.", "properties": { "schema_version": { "description": "Catalog schema used to deserialize `template`.", "type": "string" }, "slug": { "description": "Stable service family identifier.", "type": "string" }, "template": { "$ref": "#/components/schemas/ProjectTemplate", "description": "Exact resolved release from which this project was created/upgraded." }, "version": { "description": "Applied template release.", "type": "string" } }, "required": [ "schema_version", "slug", "version", "template" ], "type": "object" }, "ServiceTemplateInstanceResponse": { "properties": { "applied": { "$ref": "#/components/schemas/ServiceTemplateInstance" }, "catalog_drift": { "description": "The catalog definition changed without a version bump. Applying it is\nintentionally blocked because mutable releases make upgrades and\nrollbacks non-reproducible.", "type": "boolean" }, "catalog_error": { "description": "User-safe explanation when the active catalog could not provide this\nservice family. The applied snapshot remains authoritative and editable.", "type": [ "string", "null" ] }, "changes": { "items": { "$ref": "#/components/schemas/ServiceTemplateUpgradeChange" }, "type": "array" }, "latest": { "oneOf": [ { "$ref": "#/components/schemas/ServiceTemplateInstance", "description": "Latest release for the same service family. Absent when the catalog no\nlonger carries the template; the applied snapshot is still usable." }, { "type": "null" } ] }, "missing_services": { "description": "Managed service families that must be linked before this release can be\napplied. Existing links are never removed automatically.", "items": { "type": "string" }, "type": "array" }, "project_id": { "format": "int32", "type": "integer" }, "required_configuration": { "description": "Required target inputs that are not currently configured and cannot be\nfilled from a template default or generator.", "items": { "$ref": "#/components/schemas/EnvVarTemplate" }, "type": "array" }, "upgrade_available": { "type": "boolean" } }, "required": [ "project_id", "applied", "upgrade_available", "catalog_drift", "changes", "required_configuration", "missing_services" ], "type": "object" }, "ServiceTemplateUpgradeChange": { "description": "One reviewable change between the project's applied service release and\nthe current catalog release. Values contain public template metadata only;\nproject environment values and secrets never enter this response.", "properties": { "current": { "type": [ "string", "null" ] }, "field": { "type": "string" }, "kind": { "$ref": "#/components/schemas/ServiceTemplateChangeKind" }, "target": { "type": [ "string", "null" ] } }, "required": [ "field", "kind" ], "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" }, "id": { "format": "int32", "type": "integer" }, "occurred_at": { "example": "2024-01-01T00:00:00", "format": "date-time", "type": "string" }, "request_path": { "type": "string" }, "request_query": { "type": [ "string", "null" ] } }, "required": [ "id", "event_name", "occurred_at", "event_data", "request_path" ], "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": { "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" ] } }, "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": { "batchId": { "description": "Client-generated id, stable across retries of the same batch. When\npresent the append is idempotent; omitted, delivery is at-least-once.", "type": [ "string", "null" ] }, "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" ] }, "visitorId": { "description": "Client-generated visitor id, used only when the request carries no\nTemps-issued `_temps_visitor_id` cookie — i.e. Temps is used purely as\nan analytics backend for an app it doesn't deploy/proxy (gotempsh/temps#848).\nThe SDK already sends this today via `getSessionMetadata()`.", "type": [ "string", "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" }, "SetAlternateSourcesRequest": { "description": "Opt a project in or out of accepting deployments from a source other than\nits configured `source_type`.\n\nUnlike `ChangeProjectSourceRequest` this leaves `source_type` alone, so a\nGit project keeps its repository, branch, webhook auto-deploy and\nrollback-rebuild behaviour and merely gains the ability to also be deployed\nfrom an uploaded source archive.", "properties": { "allow_alternate_sources": { "description": "`true` to also accept uploaded source archives, `false` to restrict the\nproject to its configured source again.", "type": "boolean" } }, "required": [ "allow_alternate_sources" ], "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" }, "SetHttpCheckEnabled": { "properties": { "enabled": { "type": "boolean" } }, "required": [ "enabled" ], "type": "object" }, "SetManagedRecordRequest": { "description": "Request to create or update a managed DNS record", "properties": { "content": { "$ref": "#/components/schemas/DnsRecordContent", "description": "Record content (determines the record type)" }, "domain": { "description": "Domain (any FQDN under a managed zone)", "example": "example.com", "type": "string" }, "environment_id": { "description": "Environment this record belongs to (stamped into the ownership marker)", "format": "int32", "type": [ "integer", "null" ] }, "name": { "description": "Record name relative to the zone (\"@\" for apex)", "example": "app", "type": "string" }, "project_id": { "description": "Project this record belongs to (stamped into the ownership marker)", "format": "int32", "type": [ "integer", "null" ] }, "proxied": { "description": "Proxy through the provider's CDN (Cloudflare orange-cloud). Also\nenabled by the managed domain's `proxied_by_default`.", "type": [ "boolean", "null" ] }, "ttl": { "description": "TTL in seconds (None = provider default)", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] } }, "required": [ "domain", "name", "content" ], "type": "object" }, "SetNodePublicIngressRequest": { "properties": { "enabled": { "type": "boolean" } }, "required": [ "enabled" ], "type": "object" }, "SetNodePublicIngressResponse": { "properties": { "enabled": { "type": "boolean" }, "node_id": { "format": "int32", "type": "integer" } }, "required": [ "node_id", "enabled" ], "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" }, "SetWireguardMeshHubRequest": { "description": "Body of `PUT /nodes/wireguard/hub`.", "properties": { "hub": { "$ref": "#/components/schemas/WireguardMeshHubTarget" } }, "required": [ "hub" ], "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" }, "SetupMfaRequest": { "properties": { "current_password": { "description": "Required to enroll MFA on an account that has a password set.\nOmit (or leave empty) for SSO-only accounts with no local password.", "example": "current_password_value", "type": [ "string", "null" ] } }, "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" }, "SilenceAlarmRequest": { "description": "Request body for `POST .../alarms/{alarm_id}/silence`.", "properties": { "duration_hours": { "description": "How long to mute this alarm (and future re-fires of the same\ntype/scope) for, in hours. Must be between 1 and 168 (7 days).", "format": "int64", "type": "integer" } }, "required": [ "duration_hours" ], "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" }, "SkipHostnameRecord": { "description": "A conflicting generated hostname the user chose to leave untouched. The\napply refuses it when the conflict changed after the preview, so a skip\nnever covers a record state the user did not review.", "properties": { "name": { "description": "The conflict's `name`.", "example": "pr-12.preview.example.com", "type": "string" }, "record_type": { "description": "The conflict's `record_type`.", "example": "A", "type": "string" }, "revision": { "description": "The conflict's `revision`, from the preview the user reviewed.", "type": "string" } }, "required": [ "name", "record_type", "revision" ], "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 properties by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where props->'user'->>'plan' = 'premium',\nfalling back to the legacy `event_data` column when `props` is NULL", "properties": { "type": { "enum": [ "custom_data" ], "type": "string" }, "value": { "description": "Match custom event properties by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where props->'user'->>'plan' = 'premium',\nfalling back to the legacy `event_data` column when `props` is NULL", "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" }, "SnapshotResponse": { "description": "Single snapshot as returned by the API.", "properties": { "backend": { "type": "string" }, "content_digest": { "type": "string" }, "created_at": { "type": "string" }, "id": { "type": "string" }, "image_ref": { "type": [ "string", "null" ] }, "label": { "type": [ "string", "null" ] }, "project_id": { "format": "int32", "type": [ "integer", "null" ] }, "size_bytes": { "format": "int64", "type": "integer" }, "status": { "type": "string" }, "updated_at": { "type": "string" } }, "required": [ "id", "status", "backend", "content_digest", "size_bytes", "created_at", "updated_at" ], "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" ] }, "expires_at": { "description": "When retention deletes this backup, if it is governed by a schedule.\n`null` for manual backups and S3-scan entries — those are kept until\nsomeone deletes them.", "example": "2024-02-14T14:30:00.123Z", "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" ] }, "destination": { "description": "Optional path relative to the sandbox work directory.", "type": [ "string", "null" ] }, "git_connection_id": { "format": "int32", "type": [ "integer", "null" ] }, "password": { "type": [ "string", "null" ] }, "revision": { "type": [ "string", "null" ] }, "strip_git_metadata": { "description": "Remove `/.git` after cloning. Requires destination.", "type": "boolean" }, "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- `External`: Telemetry only, without hosting\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": [ "external", "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" ] }, "sessionId": { "description": "Client-generated session id fallback (see `visitor_id`).", "type": [ "string", "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" ] }, "visitorId": { "description": "Client-generated visitor id, used only when the request carries no\nTemps-issued `_temps_visitor_id` cookie — i.e. Temps is used purely as\nan analytics backend for an app it doesn't deploy/proxy (gotempsh/temps#848).", "type": [ "string", "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" ] }, "confirm_cross_service": { "description": "Explicit confirmation for a destructive cross-service restore.\n\nRestoring in place (or PITR in place) onto a service that did not\nproduce the backup — or from a raw backup location whose origin is\nunknown — overwrites the target with another service's data. Such a\nrequest is rejected with `409 Conflict` unless this is `true`. The\nconfirmation is recorded in the audit log. Ignored for modes that\nprovision a new service and for same-service restores.", "type": "boolean" }, "s3_source_id": { "description": "S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used.", "format": "int32", "type": [ "integer", "null" ] } }, "type": "object" } ] }, "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": { "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" ] }, "exclude_synthetic": { "description": "Exclude Temps status-monitor traffic, including legacy rows written\nbefore monitor requests received their own `request_source` value.", "type": "boolean" }, "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" }, "StorageSummary": { "description": "Storage summary returned by `GET /v1/sandbox-snapshots/storage-summary`.", "properties": { "available_disk_bytes": { "description": "Available bytes on the snapshots filesystem, or `null` when the\nplatform check is not yet implemented (deferred — see `available_disk_space()`).\nAPI consumers MUST treat `null` as \"unknown\" rather than \"zero bytes\navailable\". A `Some(0)` would incorrectly block snapshot creation.", "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "quota_bytes": { "description": "Per-user quota in bytes.", "format": "int64", "minimum": 0, "type": "integer" }, "snapshot_count": { "description": "Number of `ready` snapshots.", "format": "int32", "minimum": 0, "type": "integer" }, "total_bytes": { "description": "Total bytes used by all `ready` snapshots for this user.", "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "total_bytes", "snapshot_count", "quota_bytes" ], "type": "object" }, "StreamStructuredOutputRequest": { "properties": { "cache_key": { "description": "Optional screen-owned cache identity. Prompt and schema hashes are also\nincluded automatically, preventing stale output when input data changes.", "type": [ "string", "null" ] }, "cache_ttl_seconds": { "description": "Backend cache lifetime in seconds (default 60, clamped to 1-300).", "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "model": { "description": "Optional enabled model id for the selected key.", "type": [ "string", "null" ] }, "prompt": { "description": "The complete, already-authorized context and instructions for the model.", "type": "string" }, "provider_key_id": { "description": "Optional configured gateway key. Omit to use the active gateway key.\nHost subscription CLIs are intentionally not accepted here.", "format": "int32", "type": [ "integer", "null" ] }, "purpose": { "description": "Stable product use-case identifier, for example `api_traffic.summary`.", "type": "string" }, "refresh": { "description": "Bypass any matching backend cache entry and replace it with this result.", "type": "boolean" }, "schema": { "description": "JSON Schema describing the required response object." }, "thinking_level": { "description": "Optional normalized reasoning depth advertised for the selected model.", "type": [ "string", "null" ] } }, "required": [ "purpose", "prompt", "schema" ], "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" }, "SupervisorKind": { "description": "What (if anything) will restart the process after it exits.", "enum": [ "systemd", "launchd", "container", "none" ], "type": "string" }, "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" ] }, "preset": { "description": "Cached default-branch preset slug, or __undetected__ for uninspected repositories.", "type": [ "string", "null" ] }, "private": { "type": [ "boolean", "null" ] }, "search": { "type": [ "string", "null" ] }, "sort": { "type": [ "string", "null" ] }, "updated_after": { "format": "date-time", "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" }, "TelemetryEventCategory": { "description": "Area an event belongs to, for operator-facing disclosure (see\n[`TelemetryEventKind::category`]). Serialized as snake_case.", "enum": [ "instance", "deployments", "projects", "git", "domains", "services", "feature_activation", "ai", "configuration", "health" ], "type": "string" }, "TelemetryEventInfo": { "description": "One event this binary can send.", "properties": { "category": { "$ref": "#/components/schemas/TelemetryEventCategory" }, "name": { "description": "Wire name, e.g. `deploy_succeeded`.", "example": "deploy_succeeded", "type": "string" } }, "required": [ "name", "category" ], "type": "object" }, "TelemetryGapWindowResponse": { "description": "A gap window as the client renders it.", "properties": { "dropped_bytes": { "format": "int64", "type": "integer" }, "dropped_spans": { "format": "int64", "type": "integer" }, "ended_at": { "format": "date-time", "type": "string" }, "message": { "description": "The sentence shown to the operator. Sent by the server so the client\nnever has to map an enum to prose and never renders a bare enum name.", "type": "string" }, "project_id": { "format": "int32", "type": "integer" }, "reason": { "$ref": "#/components/schemas/TelemetryWriteIntervalReason" }, "started_at": { "format": "date-time", "type": "string" } }, "required": [ "project_id", "started_at", "ended_at", "dropped_spans", "dropped_bytes", "reason", "message" ], "type": "object" }, "TelemetryStatusResponse": { "description": "Current anonymous telemetry state and disclosure.", "properties": { "admin_preference": { "description": "The admin's stored choice; `null` when nobody has chosen yet.", "type": [ "boolean", "null" ] }, "anonymous_id": { "description": "Random identifier events are reported under. Not derived from the\nhost, domain or any account. `null` if the reporter could not start.", "type": [ "string", "null" ] }, "can_manage": { "description": "Whether the caller may change the setting (instance admins only).", "type": "boolean" }, "default_enabled": { "description": "The built-in default that applies when nobody has chosen.", "type": "boolean" }, "enabled": { "description": "Whether this server is sending anonymous telemetry right now.", "type": "boolean" }, "endpoint_host": { "description": "Host events are sent to.", "example": "telemetry.temps.sh", "type": [ "string", "null" ] }, "env_opted_out": { "description": "`TEMPS_TELEMETRY` forces telemetry off on this server. The console\ncannot override it; remove the variable and restart to change.", "type": "boolean" }, "env_var": { "description": "Name of the environment variable that forces telemetry off.", "example": "TEMPS_TELEMETRY", "type": "string" }, "events": { "description": "Every event this binary can send.", "items": { "$ref": "#/components/schemas/TelemetryEventInfo" }, "type": "array" }, "privacy_doc_url": { "description": "Documentation of what is collected and what is never collected.", "type": "string" }, "source": { "$ref": "#/components/schemas/TelemetryStatusSource", "description": "What decided `enabled`." }, "temps_version": { "description": "Version string stamped on every event.", "type": [ "string", "null" ] } }, "required": [ "enabled", "source", "env_opted_out", "env_var", "default_enabled", "can_manage", "events", "privacy_doc_url" ], "type": "object" }, "TelemetryStatusSource": { "description": "What decided the current telemetry state.", "enum": [ "environment", "admin_setting", "default", "unavailable" ], "type": "string" }, "TelemetryWriteIntervalReason": { "description": "Why an interval opened.", "enum": [ "operator", "cloud_disconnected", "quota_exhausted", "credential_rejected", "queue_overflow_spill", "cloud_recovered" ], "type": "string" }, "TelemetryWriteIntervalResponse": { "description": "One entry of the write-mode ledger.", "properties": { "effective_from": { "format": "date-time", "type": "string" }, "effective_to": { "format": "date-time", "type": [ "string", "null" ] }, "message": { "type": "string" }, "mode": { "$ref": "#/components/schemas/CloudTelemetryWriteMode" }, "reason": { "$ref": "#/components/schemas/TelemetryWriteIntervalReason" } }, "required": [ "mode", "effective_from", "reason", "message" ], "type": "object" }, "TemplateKind": { "description": "Where a template is presented in the project creation flow.", "enum": [ "starter", "service" ], "type": "string" }, "TemplateResources": { "description": "Resource profile required by a curated template. CPU values use the same\nmicrocore unit as project deployment configuration; memory values are MiB.", "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" }, "TemplateResponse": { "description": "Response type for a single template", "properties": { "command": { "description": "Optional command passed to the image entrypoint.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "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" }, "kind": { "$ref": "#/components/schemas/TemplateKind", "description": "Gallery this template belongs to." }, "managed_service_bindings": { "additionalProperties": { "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" }, "type": "object" }, "description": "Managed-service environment aliases used at deployment time.", "propertyNames": { "type": "string" }, "type": "object" }, "name": { "description": "Display name", "type": "string" }, "preset": { "description": "Framework/preset to use", "type": "string" }, "resources": { "oneOf": [ { "$ref": "#/components/schemas/TemplateResources", "description": "Curated CPU/memory profile applied when the project is created." }, { "type": "null" } ] }, "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" }, "version": { "description": "Immutable release identifier for service templates.", "type": "string" } }, "required": [ "slug", "name", "version", "kind", "git", "preset", "tags", "features", "services", "env_vars", "is_featured", "managed_service_bindings" ], "type": "object" }, "TenantResourceCeilings": { "description": "Ceilings on the resource overrides a *tenant* may set for their own\nproject or environment.\n\nThe knobs these bound (`memory_limit`, `max_concurrent_connections`, the\nrequest/idle timeouts) are deliberately uncapped-by-sentinel: `0` means\n\"unlimited\". That is the right default for a single-team self-hosted\ninstall, where the person editing a project *is* the operator. It is the\nwrong default on a shared host, where it lets one project opt out of the\noperator's protection and take the node — or the shared proxy's connection\nbudget — down with it.\n\nEvery ceiling here is therefore **off by default**, and turning one on is\nwhat makes the corresponding tenant override enforceable. A caller holding\n`Permission::SettingsWrite` (operators: `Admin`/`PlatformAdmin`, never\n`Role::User`) may still exceed them — the ceiling constrains tenants, not\nthe operator who set it.\n\nViolations are **rejected, not clamped**: silently rewriting a value the\nuser asked for leaves them debugging a limit they believe they removed,\nand self-hosted operators have no support channel to ask.", "properties": { "allow_unlimited_request_timeouts": { "default": true, "description": "Whether a project/environment may set a request, SSE or WebSocket\ntimeout of `0` (\"no timeout\"). `true` (the default) preserves current\nbehaviour.\n\nNonzero tenant timeouts need no ceiling here: they are already clamped\nto [`RequestTimeoutSettings::ceiling`] at resolution time. `0` escapes\nthat clamp by construction — it means \"no timeout is configured\", so\nthere is nothing to clamp — which is precisely the hole this closes.", "type": "boolean" }, "max_concurrent_connections": { "default": 0, "description": "Largest `max_concurrent_connections` a project/environment may set.\n`0` (the default) leaves it unenforced.\n\nAs with memory, a project value of `0` means unlimited and is refused\nwhenever this ceiling is set.", "example": 200, "format": "int32", "minimum": 0, "type": "integer" }, "max_memory_limit_mb": { "default": 0, "description": "Largest `memory_limit` (MB) a project/environment may set for its\ncontainers. `0` (the default) leaves it unenforced.\n\nA project value of `0` means \"no cgroup limit at all\", so it is\nrefused whenever this ceiling is set — that is the case that OOMs the\nhost, not merely a large number.", "example": 4096, "format": "int32", "minimum": 0, "type": "integer" } }, "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\", \"openrouter\"", "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" }, "ThreadArtifactResponse": { "properties": { "created_at": { "type": "string" }, "kind": { "type": "string" }, "payload": {}, "public_id": { "type": "string" }, "schema_version": { "format": "int32", "type": "integer" }, "status": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "updated_at": { "type": "string" } }, "required": [ "public_id", "kind", "schema_version", "payload", "status", "created_at", "updated_at" ], "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" }, "latency_count": { "description": "Number of requests in this bucket that recorded a latency value.", "format": "int64", "type": "integer" }, "p50_response_time_ms": { "description": "p50 response time in milliseconds (0 when the bucket has no timings)", "format": "double", "type": "number" }, "p95_response_time_ms": { "description": "p95 response time in milliseconds (0 when the bucket has no timings)", "format": "double", "type": "number" }, "p99_response_time_ms": { "description": "p99 response time in milliseconds (0 when the bucket has no timings)", "format": "double", "type": "number" }, "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", "latency_count", "avg_response_time_ms", "p50_response_time_ms", "p95_response_time_ms", "p99_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" }, "TraceProject": { "properties": { "id": { "format": "int32", "type": "integer" }, "name": { "type": "string" }, "slug": { "type": "string" } }, "required": [ "id", "name", "slug" ], "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" }, "TraefikDiscoveredRouteListResponse": { "description": "Paginated discovered routes, plus the hosts that were found and rejected.", "properties": { "conflicts": { "description": "Labelled containers found by the last reconciliation that were NOT\nadopted (host owned by a Temps route, or claimed by another container).\nThese have no row of their own — without surfacing them here the\noperator sees nothing at all for a container they labelled.", "items": { "$ref": "#/components/schemas/TraefikDiscoveryConflictResponse" }, "type": "array" }, "discovery_running": { "description": "`false` when the watcher isn't running, so a client can explain an\nempty list as \"discovery is off\" rather than \"nothing was found\".", "type": "boolean" }, "page": { "format": "int64", "minimum": 0, "type": "integer" }, "page_size": { "format": "int64", "minimum": 0, "type": "integer" }, "routes": { "items": { "$ref": "#/components/schemas/TraefikDiscoveredRouteResponse" }, "type": "array" }, "total": { "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "routes", "total", "page", "page_size", "conflicts", "discovery_running" ], "type": "object" }, "TraefikDiscoveredRouteResponse": { "description": "One row of `traefik_discovered_routes`, annotated for an operator.", "properties": { "active": { "description": "Whether this route is currently served by the proxy.", "type": "boolean" }, "contested_by": { "description": "Other labelled containers that claim this host and lost the collision.\nNon-empty means someone's container is silently not being routed.", "items": { "type": "string" }, "type": "array" }, "created_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": "string" }, "enabled": { "type": "boolean" }, "host": { "type": "string" }, "id": { "format": "int32", "type": "integer" }, "inactive_reason": { "description": "Why it isn't, when `active` is false.", "type": [ "string", "null" ] }, "last_seen_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": "string" }, "network": { "type": "string" }, "router_name": { "type": "string" }, "target_container_id": { "type": "string" }, "target_container_name": { "type": "string" }, "target_host_port": { "description": "Host-published port, used on baremetal installs where the proxy cannot\nresolve container names.", "format": "int32", "type": [ "integer", "null" ] }, "target_port": { "format": "int32", "type": "integer" }, "tls": { "type": "boolean" }, "tls_certificate": { "oneOf": [ { "$ref": "#/components/schemas/TraefikRouteTlsBlock", "description": "TLS authorization state for this host (ADR-041). Present only when a\n`traefik_route_certificates` row exists. `null` means no operator has\never authorized TLS for this host — the container label's `tls` field\n(above) records what the label says, but this is what has been acted on." }, { "type": "null" } ] }, "updated_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": "string" } }, "required": [ "id", "host", "router_name", "target_container_id", "target_container_name", "target_port", "network", "tls", "enabled", "active", "contested_by", "last_seen_at", "created_at", "updated_at" ], "type": "object" }, "TraefikDiscoveryConflictResponse": { "description": "A labelled container that was found but deliberately **not** adopted.", "properties": { "container_id": { "type": "string" }, "container_name": { "type": "string" }, "detail": { "description": "Human-readable explanation of the conflict.", "type": "string" }, "host": { "type": "string" }, "reason": { "description": "Machine-readable discriminator: `owned_by_temps_route` or\n`claimed_by_another_container`.", "type": "string" }, "router_name": { "description": "Traefik router name the host came from.", "type": "string" }, "winner_container_name": { "description": "Container that holds the host instead, when the conflict is between two\ndiscovered containers.", "type": [ "string", "null" ] } }, "required": [ "host", "container_id", "container_name", "router_name", "reason", "detail" ], "type": "object" }, "TraefikDiscoverySetupResponse": { "description": "How an operator turns discovery on. Always returned, including when\ndiscovery is already running, so the console/CLI can render the exact\ninvocation instead of sending the reader to the docs.", "properties": { "enable_env_var": { "description": "Environment variable that opts this installation in.", "example": "TEMPS_TRAEFIK_DISCOVERY_ENABLED", "type": "string" }, "example": { "description": "A concrete, copy-pasteable example of enabling it.", "type": "string" }, "network_env_var": { "description": "Environment variable overriding the watched Docker network.", "example": "TEMPS_TRAEFIK_DISCOVERY_NETWORK", "type": "string" }, "requires_restart": { "description": "These are read once at process start: changing them needs a restart.", "type": "boolean" } }, "required": [ "enable_env_var", "network_env_var", "example", "requires_restart" ], "type": "object" }, "TraefikDiscoveryStatusResponse": { "description": "Capability + status of Traefik label discovery on this instance.", "properties": { "configured": { "description": "`true` only when the watcher is actually running in this process.\n`false` means \"not turned on here\", never \"not supported\" — the setup\nblock below always says how to turn it on.", "type": "boolean" }, "discovered_route_count": { "description": "Rows currently in `traefik_discovered_routes` (all networks).", "format": "int64", "minimum": 0, "type": "integer" }, "enabled": { "description": "Whether `TEMPS_TRAEFIK_DISCOVERY_ENABLED` resolved to true. Can be\n`true` while `configured` is `false` (e.g. Docker unreachable).", "type": "boolean" }, "enabled_route_count": { "description": "Of those, how many are enabled and therefore in the live route table.", "format": "int64", "minimum": 0, "type": "integer" }, "last_reconciliation": { "oneOf": [ { "$ref": "#/components/schemas/TraefikReconciliationResponse", "description": "Last reconciliation pass, absent until the first one completes." }, { "type": "null" } ] }, "network": { "description": "Docker network being watched, or the one that *would* be watched.", "type": "string" }, "poll_interval_seconds": { "description": "Interval of the full reconciliation safety net.", "format": "int64", "minimum": 0, "type": "integer" }, "reason": { "description": "Why discovery isn't active, when `configured` is false.", "type": [ "string", "null" ] }, "setup": { "$ref": "#/components/schemas/TraefikDiscoverySetupResponse" } }, "required": [ "configured", "enabled", "network", "poll_interval_seconds", "setup", "discovered_route_count", "enabled_route_count" ], "type": "object" }, "TraefikReconciliationResponse": { "description": "Summary of the most recent reconciliation pass.", "properties": { "completed_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": "string" }, "conflicts": { "items": { "$ref": "#/components/schemas/TraefikDiscoveryConflictResponse" }, "type": "array" }, "containers_scanned": { "minimum": 0, "type": "integer" }, "network": { "type": "string" }, "routes_removed": { "minimum": 0, "type": "integer" }, "routes_unchanged": { "minimum": 0, "type": "integer" }, "routes_upserted": { "minimum": 0, "type": "integer" }, "skipped_temps_managed": { "description": "Containers skipped because Temps deployed them (they already have a\nroute and must never re-derive one from labels they control).", "minimum": 0, "type": "integer" } }, "required": [ "network", "containers_scanned", "skipped_temps_managed", "routes_upserted", "routes_unchanged", "routes_removed", "conflicts", "completed_at" ], "type": "object" }, "TraefikRouteTlsBlock": { "description": "TLS state for a single discovered route (ADR-041 §3/§4).\n\nAbsent when no `traefik_route_certificates` row exists for this host.\nNever `null` on a host where `cert_authorized = true`.", "properties": { "authorized_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": "string" }, "authorized_container_id": { "description": "Container ID that was authorized. Used for drift comparison.", "type": [ "string", "null" ] }, "authorized_container_name": { "type": [ "string", "null" ] }, "cert_authorized": { "description": "The operator has explicitly authorized TLS for this host.", "type": "boolean" }, "container_drift": { "description": "`true` when the currently-serving container differs from the one\nthat was authorized. Requires operator acknowledgment.", "type": "boolean" }, "container_drift_detected_at": { "description": "When drift was first detected.", "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": "string" }, "current_container_name": { "description": "Name of the container that currently holds the host (for the drift UI).", "type": [ "string", "null" ] }, "days_remaining": { "description": "Days until expiry.", "format": "int64", "type": [ "integer", "null" ] }, "imported_at": { "example": "2026-01-01T00:00:00Z", "format": "date-time", "type": "string" }, "not_after": { "description": "ISO 8601 expiry time of the current certificate, if one exists.", "type": [ "string", "null" ] }, "renewal_method": { "description": "`\"http-01\"` or `\"dns-01\"`.", "type": [ "string", "null" ] }, "serving": { "description": "`true` when the proxy is currently loading a cert for this host.", "type": "boolean" }, "source": { "description": "`\"acme\"` or `\"imported\"`.", "type": [ "string", "null" ] }, "status": { "description": "Certificate status as reported by the `domains` row, e.g. `\"active\"`.", "type": [ "string", "null" ] } }, "required": [ "cert_authorized", "serving", "container_drift", "container_drift_detected_at", "authorized_at", "imported_at" ], "type": "object" }, "TrafficAggregationRequest": { "properties": { "dimensions": { "description": "Zero to four grouping dimensions. Zero returns one overall rollup;\nmultiple dimensions form a tuple.", "items": { "$ref": "#/components/schemas/TrafficDimension" }, "type": "array" }, "end_time": { "format": "date-time", "type": "string" }, "environment_id": { "format": "int32", "type": [ "integer", "null" ] }, "filters": { "items": { "$ref": "#/components/schemas/TrafficFilter" }, "type": "array" }, "include_synthetic": { "description": "Include Temps status-monitor requests. They are excluded by default.", "type": "boolean" }, "metrics": { "description": "Aggregates to calculate. Unrequested response fields remain null.", "items": { "$ref": "#/components/schemas/TrafficMetric" }, "type": "array" }, "order_by": { "description": "Ordered sort keys. Multiple keys provide stable pagination when the\nprimary metric ties. Every field must be requested/grouped.", "items": { "$ref": "#/components/schemas/TrafficOrderBy" }, "type": "array" }, "page": { "format": "int64", "minimum": 0, "type": "integer" }, "page_size": { "format": "int64", "minimum": 0, "type": "integer" }, "start_time": { "format": "date-time", "type": "string" } }, "required": [ "start_time", "end_time", "dimensions", "metrics" ], "type": "object" }, "TrafficAggregationResponse": { "properties": { "dimensions": { "items": { "$ref": "#/components/schemas/TrafficDimension" }, "type": "array" }, "metrics": { "items": { "$ref": "#/components/schemas/TrafficMetric" }, "type": "array" }, "page": { "format": "int64", "minimum": 0, "type": "integer" }, "page_size": { "format": "int64", "minimum": 0, "type": "integer" }, "rows": { "items": { "$ref": "#/components/schemas/TrafficAggregationRow" }, "type": "array" }, "synthetic_excluded": { "type": "boolean" }, "total_groups": { "format": "int64", "minimum": 0, "type": "integer" }, "total_pages": { "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "rows", "total_groups", "page", "page_size", "total_pages", "dimensions", "metrics", "synthetic_excluded" ], "type": "object" }, "TrafficAggregationRow": { "properties": { "dimensions": { "items": { "$ref": "#/components/schemas/TrafficDimensionValue" }, "type": "array" }, "metrics": { "$ref": "#/components/schemas/TrafficMetricValues" } }, "required": [ "dimensions", "metrics" ], "type": "object" }, "TrafficDimension": { "enum": [ "client_ip", "method", "path", "host", "status_code", "status_class", "environment_id", "deployment_id", "request_source", "is_bot", "browser", "operating_system", "device_type", "cache_status" ], "type": "string" }, "TrafficDimensionValue": { "properties": { "dimension": { "$ref": "#/components/schemas/TrafficDimension" }, "value": { "description": "Dimensions are serialized as display-safe strings across both storage\nbackends. Null database values remain null rather than becoming empty.", "type": [ "string", "null" ] } }, "required": [ "dimension" ], "type": "object" }, "TrafficFilter": { "properties": { "dimension": { "$ref": "#/components/schemas/TrafficDimension" }, "operator": { "$ref": "#/components/schemas/TrafficFilterOperator" }, "values": { "description": "One value for scalar operators; one or more values for `in`.", "items": { "type": "string" }, "type": "array" } }, "required": [ "dimension", "operator", "values" ], "type": "object" }, "TrafficFilterOperator": { "enum": [ "eq", "not_eq", "contains", "starts_with", "in" ], "type": "string" }, "TrafficMetric": { "enum": [ "requests", "errors", "error_rate", "latency_avg", "latency_min", "latency_max", "latency_p50", "latency_p95", "latency_p99", "unique_ips", "unique_paths", "bot_requests", "robots_txt_requests", "last_seen" ], "type": "string" }, "TrafficMetricValues": { "properties": { "bot_requests": { "format": "int64", "type": [ "integer", "null" ] }, "error_rate": { "format": "double", "type": [ "number", "null" ] }, "errors": { "format": "int64", "type": [ "integer", "null" ] }, "last_seen": { "format": "date-time", "type": [ "string", "null" ] }, "latency_avg_ms": { "format": "double", "type": [ "number", "null" ] }, "latency_max_ms": { "format": "double", "type": [ "number", "null" ] }, "latency_min_ms": { "format": "double", "type": [ "number", "null" ] }, "latency_p50_ms": { "format": "double", "type": [ "number", "null" ] }, "latency_p95_ms": { "format": "double", "type": [ "number", "null" ] }, "latency_p99_ms": { "format": "double", "type": [ "number", "null" ] }, "requests": { "format": "int64", "type": [ "integer", "null" ] }, "robots_txt_requests": { "format": "int64", "type": [ "integer", "null" ] }, "unique_ips": { "format": "int64", "type": [ "integer", "null" ] }, "unique_paths": { "format": "int64", "type": [ "integer", "null" ] } }, "type": "object" }, "TrafficOrderBy": { "properties": { "direction": { "$ref": "#/components/schemas/TrafficSortDirection" }, "field": { "$ref": "#/components/schemas/TrafficOrderField" } }, "required": [ "field", "direction" ], "type": "object" }, "TrafficOrderField": { "oneOf": [ { "properties": { "field": { "$ref": "#/components/schemas/TrafficDimension" }, "kind": { "enum": [ "dimension" ], "type": "string" } }, "required": [ "field", "kind" ], "type": "object" }, { "properties": { "field": { "$ref": "#/components/schemas/TrafficMetric" }, "kind": { "enum": [ "metric" ], "type": "string" } }, "required": [ "field", "kind" ], "type": "object" } ] }, "TrafficSortDirection": { "enum": [ "asc", "desc" ], "type": "string" }, "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" }, "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" }, "UpdateAiSummaryPreferenceRequest": { "description": "Replace the instance-wide defaults inherited by every AI summary.", "properties": { "model": { "type": [ "string", "null" ] }, "provider_id": { "type": [ "string", "null" ] }, "thinking_level": { "type": [ "string", "null" ] } }, "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" }, "UpdateAnalyticsIngestKeyRequest": { "description": "Request body for a partial update.\n\n`allowed_origins` and `rate_limit_per_minute` use the three-state\ndouble-`Option` encoding: field absent = leave unchanged, explicit `null` =\nclear, value = set. Plain `Option>` alone cannot express this\nbecause serde collapses an explicit JSON `null` into the outer `None`.", "properties": { "allowed_origins": { "description": "Absent = unchanged, `null` = clear (any origin allowed), array = replace.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "name": { "description": "New operator-facing label. Absent leaves it unchanged. The column is\n`NOT NULL`, so there is no \"clear\" state — send a new label instead.", "type": [ "string", "null" ] }, "rate_limit_per_minute": { "description": "Absent = unchanged, `null` = clear (unlimited), value = replace.", "format": "int32", "type": [ "integer", "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" }, "UpdateApplicationWorkspaceRequest": { "properties": { "cpu_limit": { "format": "double", "type": [ "number", "null" ] }, "disk_limit_mb": { "format": "int64", "type": [ "integer", "null" ] }, "idle_timeout_secs": { "format": "int64", "type": [ "integer", "null" ] }, "image": { "description": "Pinned Temps-managed daemon image. Empty string restores the runtime default.\nOmit to leave the selected image unchanged. Arbitrary images are rejected.", "type": [ "string", "null" ] }, "memory_limit_mb": { "format": "int64", "type": [ "integer", "null" ] }, "pids_limit": { "format": "int64", "type": [ "integer", "null" ] }, "runtime": { "type": [ "string", "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" ] }, "service_ids": { "description": "Replace the explicit external-service selection atomically with the\nschedule update. Only meaningful when `target_all_services` resolves\nto `false`; an empty list explicitly clears the selection.", "items": { "format": "int32", "type": "integer" }, "type": [ "array", "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-rc.5\")", "example": "rustfs/rustfs:1.0.0-rc.5", "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" }, "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": [ { "$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`)." }, { "type": "null" } ] }, "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_migration_name": { "description": "Name of the migration currently running. `Some` while `phase` is\n`migrating` and a migration step is in flight.", "type": [ "string", "null" ] }, "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": [ { "$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." }, { "type": "null" } ] }, "manual_command": { "description": "The equivalent command to run by hand. Always present.", "type": "string" }, "migrations_applied": { "description": "Number of migrations applied so far. `Some` while `phase` is `migrating`.", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "migrations_total": { "description": "Total migrations to be applied. `Some` once the migrate child has\nreported its first `started` event.", "format": "int32", "minimum": 0, "type": [ "integer", "null" ] }, "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": { "$ref": "#/components/schemas/CloudflareConfig" }, "enabled": { "type": [ "boolean", "null" ] }, "name": { "type": [ "string", "null" ] } }, "required": [ "config" ], "type": "object" }, "UpdateComposeSecurityRequest": { "additionalProperties": false, "properties": { "acknowledge_legacy_migration": { "type": "boolean" }, "acknowledge_risks": { "type": "boolean" }, "expected_policy": { "$ref": "#/components/schemas/ComposeSecurityPolicy", "description": "Policy read by the editor; compared while holding the project lock." }, "policy": { "$ref": "#/components/schemas/ComposeSecurityPolicy" } }, "required": [ "policy", "expected_policy" ], "type": "object" }, "UpdateConfigBody": { "properties": { "config": { "oneOf": [ { "$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": "null" } ] } }, "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": [ { "$ref": "#/components/schemas/DashboardLayout" }, { "type": "null" } ] }, "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" ] }, "healthCheckTimeoutSeconds": { "description": "How long, in seconds (30-3600), a new deployment's containers may take\nto start and pass their readiness check before the deployment fails.\nAbsent leaves the current value unchanged; the platform default is\n300 seconds.", "format": "int32", "type": [ "integer", "null" ] }, "maxConcurrentConnections": { "description": "Project-level default cap on concurrent in-flight requests to a\nsingle environment's upstream (0 = unlimited). Environments may\noverride this. Absent leaves the current value unchanged. See\nissue #646.", "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" ] }, "requestTimeoutSeconds": { "description": "Project-level default timeout for regular (non-streaming) HTTP\nrequests, in seconds (0 = no timeout, or 1-86400). Environments may\noverride this; always clamped to the operator's global hard ceiling\nregardless of what's set here. Absent leaves the current value\nunchanged.", "format": "int32", "type": [ "integer", "null" ] }, "security": { "oneOf": [ { "$ref": "#/components/schemas/SecurityConfig" }, { "type": "null" } ] }, "sessionRecordingEnabled": { "type": [ "boolean", "null" ] }, "sseIdleTimeoutSeconds": { "description": "Project-level default idle timeout for Server-Sent Events streams, in\nseconds (0 = no timeout, or 1-86400). Environments may override this;\nalways clamped to the operator's global hard ceiling. Absent leaves\nthe current value unchanged.", "format": "int32", "type": [ "integer", "null" ] }, "websocketIdleTimeoutSeconds": { "description": "Project-level default idle timeout for WebSocket connections, in\nseconds (0 = no timeout, or 1-86400). Environments may override this;\nalways clamped to the operator's global hard ceiling. Absent leaves\nthe current value unchanged.", "format": "int32", "type": [ "integer", "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": [ { "$ref": "#/components/schemas/DnsProviderCredentials", "description": "New credentials" }, { "type": "null" } ] }, "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": [ { "$ref": "#/components/schemas/ScalewayCredentialsRequest" }, { "type": "null" } ] }, "ses_credentials": { "oneOf": [ { "$ref": "#/components/schemas/SesCredentialsRequest" }, { "type": "null" } ] }, "smtp_credentials": { "oneOf": [ { "$ref": "#/components/schemas/SmtpCredentialsRequest" }, { "type": "null" } ] }, "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" ] }, "max_concurrent_connections": { "description": "Override the proxy's cap on concurrent in-flight requests to this\nenvironment's upstream (0 = unlimited). Absent leaves the current\nvalue unchanged. Send JSON `null` to clear the override (inherit\nthe project/global default). See issue #646.", "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" ] }, "request_timeout_seconds": { "description": "Override the proxy's timeout for regular (non-streaming) HTTP requests\nto this environment, in seconds (0 = no timeout, or 1-86400). Always clamped to the\noperator's global hard ceiling regardless of what's set here.\nAbsent leaves the current value unchanged. Send JSON `null` to clear\nthe override (inherit the project/global default).", "format": "int32", "type": [ "integer", "null" ] }, "security": { "oneOf": [ { "$ref": "#/components/schemas/SecurityConfig", "description": "Security configuration for this environment (overrides project-level settings)" }, { "type": "null" } ] }, "session_recording_enabled": { "description": "Enable/disable session recording", "type": [ "boolean", "null" ] }, "sse_idle_timeout_seconds": { "description": "Override the proxy's idle timeout for Server-Sent Events streams to\nthis environment, in seconds (0 = no timeout, or 1-86400). Always clamped to the\noperator's global hard ceiling. Absent leaves the current value\nunchanged. Send JSON `null` to clear the override.", "format": "int32", "type": [ "integer", "null" ] }, "target_labels": { "description": "Label selector for node-based scheduling (overrides project-level setting).\nSend an empty object to clear the environment-level override.\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).\nSend an empty list to clear the environment-level override.", "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" ] }, "websocket_idle_timeout_seconds": { "description": "Override the proxy's idle timeout for WebSocket connections to this\nenvironment, in seconds (0 = no timeout, or 1-86400). Always clamped to the operator's\nglobal hard ceiling. Absent leaves the current value unchanged. Send\nJSON `null` to clear the override.", "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": { "description": "Assignee (email by convention).\n- `Some(\"user@example.com\")` — sets the assignee.\n- `Some(\"\")` (empty string) — clears the current assignment (sets to null).\n- `null` / field omitted — leaves the existing value unchanged.", "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": [ { "$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```" }, { "type": "null" } ] }, "pull_only_root_directory": { "description": "When true, deploy clones only `directory`. Ignored when directory is the repo root.", "type": [ "boolean", "null" ] }, "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" ] }, "proxied_by_default": { "description": "Default proxy mode for newly managed records; `false` is an explicit override.", "type": [ "boolean", "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": [ { "$ref": "#/components/schemas/DetectionConfig", "description": "Replaces the detector wholesale when present (absent = leave unchanged)." }, { "type": "null" } ] }, "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" }, "UpdateMonitorRequest": { "properties": { "check_path": { "type": "string" } }, "required": [ "check_path" ], "type": "object" }, "UpdateNotificationEmailProviderRequest": { "properties": { "config": { "$ref": "#/components/schemas/EmailConfig" }, "enabled": { "type": [ "boolean", "null" ] }, "name": { "type": [ "string", "null" ] } }, "required": [ "config" ], "type": "object" }, "UpdateNotificationRouteRequest": { "properties": { "enabled": { "type": [ "boolean", "null" ] }, "max_severity": { "type": [ "string", "null" ] }, "min_severity": { "type": [ "string", "null" ] }, "name": { "type": [ "string", "null" ] }, "provider_ids": { "items": { "format": "int32", "type": "integer" }, "type": [ "array", "null" ] } }, "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" }, "UpdatePermissionModeRequest": { "properties": { "permission_mode": { "description": "Provider permission mode to persist. During a running turn only `Auto`\n(`full-access`) can be applied because provider CLI launch flags cannot\nbe safely reduced after the process has started.", "type": "string" } }, "required": [ "permission_mode" ], "type": "object" }, "UpdatePreferencesRequest": { "properties": { "preferences": { "$ref": "#/components/schemas/NotificationPreferencesResponse" } }, "required": [ "preferences" ], "type": "object" }, "UpdateProjectCloudTelemetryRequest": { "description": "Body for changing a project's Cloud telemetry settings.\n\nBoth fields are optional and independent: an operator raising fidelity and\none flipping the write mode are two different acts, and forcing a client to\nsend both would make each one able to clobber the other.", "properties": { "analytics_write_mode": { "oneOf": [ { "$ref": "#/components/schemas/CloudAnalyticsWriteMode", "description": "ADR-043 §1: the independent switch for non-span telemetry (metrics\nunder Phase C1). Orthogonal to `write_mode` — a project may be\nCloud-primary for spans and local for analytics, or vice versa." }, { "type": "null" } ] }, "attribute_allowlist": { "items": { "type": "string" }, "type": [ "array", "null" ] }, "fidelity": { "oneOf": [ { "$ref": "#/components/schemas/CloudTelemetryFidelity" }, { "type": "null" } ] }, "write_mode": { "oneOf": [ { "$ref": "#/components/schemas/CloudTelemetryWriteMode" }, { "type": "null" } ] } }, "type": "object" }, "UpdateProjectDeliverySettingsRequest": { "properties": { "default_profile_id": { "format": "int32", "type": [ "integer", "null" ] }, "environment_overrides": { "items": { "$ref": "#/components/schemas/EnvironmentDeliveryOverride" }, "type": "array" } }, "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": { "compose_services": { "description": "Docker Compose services allowed to read this secret, by compose\nservice name. Empty (the default) delivers it to every service in the\nstack, which is how secrets behaved before scoping existed.\n\nIgnored by non-Compose presets: those deploy a single container, which\nalways receives every secret in scope for its environment.", "items": { "type": "string" }, "type": "array" }, "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_api_traffic_summary_enabled": { "description": "Opt in to AI summarization of API traffic analytics.", "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" ] }, "image_retention_hours": { "description": "How long (hours) to retain built Docker images before nightly cleanup removes them.\nSet to null to use the system default. Valid range: 1–8760.\n\nOmitting the key leaves the current value unchanged; sending an explicit\n`null` clears the per-project override. `skip_serializing_if` keeps the\nround-trip honest — re-serializing a request that omitted the key must\nnot emit `\"image_retention_hours\": null`, which would mean \"reset\".", "format": "int32", "type": [ "integer", "null" ] }, "main_branch": { "type": [ "string", "null" ] }, "name": { "description": "Human-facing project display name. Unlike `slug` this is not part of any\nURL and is not required to be unique. Changing it also changes the\n`OTEL_SERVICE_NAME` injected into subsequent deployments.", "type": [ "string", "null" ] }, "preset": { "type": [ "string", "null" ] }, "preset_config": { "oneOf": [ { "$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```" }, { "type": "null" } ] }, "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" ] }, "vulnerability_scanning_enabled": { "description": "Opt in to Trivy vulnerability scanning of this project's deployed Docker\nimages (post-deployment scan + daily rescans). Off by default.", "type": [ "boolean", "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" }, "UpdateProviderModelRequest": { "properties": { "is_enabled": { "type": "boolean" } }, "required": [ "is_enabled" ], "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" }, "UpdateSandboxPlacementBody": { "additionalProperties": false, "description": "Replace the sandbox placement allow-list.", "properties": { "allowed_node_ids": { "description": "Node ids allowed to run new sandboxes; `0` is the control plane.\nRequired: `null` allows every node, `[]` stops new sandboxes from\nbeing created anywhere. A body without this member is rejected, so\nan empty `{}` can never silently mean \"every node\". Existing\nsandboxes keep running wherever they are.", "example": [ 0, 3 ], "items": { "format": "int32", "type": "integer" }, "type": [ "array", "null" ] } }, "required": [ "allowed_node_ids" ], "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" }, "UpdateServiceTemplateRuntimeRequest": { "description": "Complete replacement for the editable runtime of a single-container\nservice-template project. Runtime and resource fields are written to the\nsame project row in one transaction.", "properties": { "command": { "description": "Empty means use the image's own default command.", "items": { "type": "string" }, "type": "array" }, "cpuLimit": { "format": "int32", "type": [ "integer", "null" ] }, "cpuRequest": { "format": "int32", "type": [ "integer", "null" ] }, "exposedPort": { "format": "int32", "type": [ "integer", "null" ] }, "healthCheckPath": { "type": "string" }, "imageRef": { "type": "string" }, "memoryLimit": { "format": "int32", "type": [ "integer", "null" ] }, "memoryRequest": { "format": "int32", "type": [ "integer", "null" ] } }, "required": [ "imageRef", "healthCheckPath" ], "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" ] }, "sessionId": { "description": "Client-generated session id fallback (see [`SpeedMetricsPayload::visitor_id`]).", "type": [ "string", "null" ] }, "visitorId": { "description": "Client-generated visitor id fallback (see [`SpeedMetricsPayload::visitor_id`]).\nRequired to identify the right row on the keyed path, where there is\nno Temps-issued cookie to fall back on.", "type": [ "string", "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" }, "UpdateTelemetrySettingsRequest": { "description": "Turn anonymous telemetry on or off.", "properties": { "enabled": { "type": "boolean" } }, "required": [ "enabled" ], "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" }, "UpdateTraefikRouteEnabledRequest": { "description": "Body of `PATCH /traefik-discovery/routes/{host}/enabled`.", "properties": { "enabled": { "description": "`false` suppresses the route without touching the container's labels;\nthe row stays visible so the operator can see what was found.", "type": "boolean" } }, "required": [ "enabled" ], "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.\nan immutable `ghcr.io/gotempsh/temps-preview-gateway@sha256:…` reference).\nEmpty resets to default.", "type": "string" } }, "required": [ "image" ], "type": "object" }, "UpgradeServiceTemplateRequest": { "properties": { "environment_variables": { "description": "Values for inputs introduced by the target release. Existing project\nvalues are preserved and cannot be overwritten through this endpoint.", "items": { "$ref": "#/components/schemas/EnvVarInput" }, "type": "array" }, "target_version": { "description": "Optimistic target selected from the preview. The server rejects a stale\ntarget if the catalog changes between preview and apply.", "type": "string" } }, "required": [ "target_version" ], "type": "object" }, "UploadFileForm": { "description": "`multipart/form-data` body of `POST /ai/v1/files`.", "properties": { "file": { "description": "A JSONL batch input file: one request per line, every line targeting\nthe same model and endpoint. At most 200 MB and 50,000 requests.", "format": "binary", "type": "string" }, "purpose": { "description": "Must be `batch`.", "type": "string" } }, "required": [ "file", "purpose" ], "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" }, "VariableHistoryDetails": { "properties": { "check_name": { "default": null, "type": [ "string", "null" ] }, "compose_services": { "default": null, "description": "Compose services a secret is limited to after a `scope_changed` event.", "items": { "type": "string" }, "type": [ "array", "null" ] }, "environment_ids": { "default": null, "description": "Secret scope after a `scope_changed` event; empty means every environment.", "items": { "format": "int32", "type": "integer" }, "type": [ "array", "null" ] }, "include_in_preview": { "default": null, "type": [ "boolean", "null" ] }, "is_secret": { "default": null, "type": [ "boolean", "null" ] }, "key": { "default": null, "type": [ "string", "null" ] }, "result": { "default": null, "oneOf": [ { "$ref": "#/components/schemas/VerificationResult" }, { "type": "null" } ] } }, "type": "object" }, "VariableHistoryEntry": { "properties": { "created_at": { "format": "date-time", "type": "string" }, "details": { "$ref": "#/components/schemas/VariableHistoryDetails" }, "id": { "format": "int64", "type": "integer" }, "kind": { "type": "string" } }, "required": [ "id", "kind", "details", "created_at" ], "type": "object" }, "VariableHistoryList": { "properties": { "items": { "items": { "$ref": "#/components/schemas/VariableHistoryEntry" }, "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" }, "VerificationResult": { "properties": { "checked_at": { "format": "date-time", "type": "string" }, "findings": { "items": { "$ref": "#/components/schemas/Finding" }, "type": "array" }, "status": { "$ref": "#/components/schemas/CheckStatus" } }, "required": [ "status", "findings", "checked_at" ], "type": "object" }, "VerifyMfaRequest": { "properties": { "code": { "type": "string" } }, "required": [ "code" ], "type": "object" }, "VerifySavedCredentialRequest": { "properties": { "verification_model": { "description": "OpenCode model in `provider/model` form, used to verify the saved secret.", "type": "string" } }, "required": [ "verification_model" ], "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" }, "VisitorActivityAssessment": { "properties": { "categories": { "items": { "type": "string" }, "type": "array" }, "evidence": { "items": { "$ref": "#/components/schemas/ActivityEvidence" }, "type": "array" }, "explanation": { "type": "string" }, "visitor_id": { "format": "int32", "type": "integer" } }, "required": [ "visitor_id", "categories", "explanation", "evidence" ], "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": [ { "$ref": "#/components/schemas/LocationGranularity" }, { "type": "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" }, "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" }, "WireguardHandshakeReport": { "properties": { "public_key": { "type": "string" }, "seconds_since_handshake": { "description": "Seconds since the last completed handshake, on the node's clock.", "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "public_key", "seconds_since_handshake" ], "type": "object" }, "WireguardMeshCheck": { "description": "One thing the control plane can tell about a node's mesh link (ADR 048\nD9), with the action that fixes it when it fails.", "properties": { "detail": { "description": "Rendered verbatim.", "type": "string" }, "fix": { "description": "What fixes it; rendered verbatim.", "type": [ "string", "null" ] }, "label": { "type": "string" }, "status": { "$ref": "#/components/schemas/WireguardMeshCheckStatus" } }, "required": [ "label", "status", "detail" ], "type": "object" }, "WireguardMeshCheckStatus": { "description": "Outcome of one mesh check.", "enum": [ "pass", "warn", "fail", "info" ], "type": "string" }, "WireguardMeshControlPlaneEntry": { "description": "The control plane's end of the mesh.", "properties": { "address": { "description": "Its mesh address.", "type": "string" }, "endpoint": { "description": "`ip:port` nodes dial. `None` when the control plane has no address\nnodes can reach (e.g. it runs on a laptop): it dials the nodes that\npublish an endpoint instead.", "type": [ "string", "null" ] }, "endpoint_is_private": { "description": "Whether `endpoint` is a private address, which nodes joining over the\ninternet cannot reach.", "type": "boolean" } }, "required": [ "address", "endpoint_is_private" ], "type": "object" }, "WireguardMeshEntry": { "description": "Managed WireGuard mesh state for the calling node. Absent when the mesh\nis off; the node then keeps its registered address as underlay.", "properties": { "cidr": { "type": "string" }, "hub": { "description": "This node is the mesh hub (ADR 048 D4): it forwards traffic between\nmembers that cannot reach each other.", "type": "boolean" }, "listen_port": { "format": "int32", "minimum": 0, "type": "integer" }, "peers": { "items": { "$ref": "#/components/schemas/WireguardMeshPeerEntry" }, "type": "array" }, "self": { "oneOf": [ { "$ref": "#/components/schemas/WireguardMeshSelfEntry", "description": "`null` until the node registers its key with\n`PUT /internal/nodes/{node_id}/network/wireguard`." }, { "type": "null" } ] } }, "required": [ "cidr", "listen_port", "peers" ], "type": "object" }, "WireguardMeshHub": { "description": "The current hub.", "properties": { "name": { "description": "`control-plane` or the node's name.", "type": "string" }, "target": { "$ref": "#/components/schemas/WireguardMeshHubTarget" } }, "required": [ "target", "name" ], "type": "object" }, "WireguardMeshHubTarget": { "description": "The member relaying for pairs that cannot reach each other (ADR 048 D4).", "oneOf": [ { "description": "No hub: pairs that cannot reach each other stay disconnected.", "properties": { "kind": { "enum": [ "none" ], "type": "string" } }, "required": [ "kind" ], "type": "object" }, { "properties": { "kind": { "enum": [ "control_plane" ], "type": "string" } }, "required": [ "kind" ], "type": "object" }, { "properties": { "kind": { "enum": [ "node" ], "type": "string" }, "node_id": { "format": "int32", "type": "integer" } }, "required": [ "node_id", "kind" ], "type": "object" } ] }, "WireguardMeshLink": { "description": "One pair of mesh members.", "properties": { "a": { "description": "`control-plane` or a node name.", "type": "string" }, "a_node_id": { "description": "`None` for the control plane.", "format": "int32", "type": [ "integer", "null" ] }, "b": { "type": "string" }, "b_node_id": { "format": "int32", "type": [ "integer", "null" ] }, "detail": { "description": "What connects them when `state` is not `direct`, or what to do.\nRendered verbatim.", "type": [ "string", "null" ] }, "last_handshake_at": { "description": "Most recent direct handshake either side reported (RFC 3339).", "type": [ "string", "null" ] }, "state": { "$ref": "#/components/schemas/WireguardMeshLinkState" } }, "required": [ "a", "b", "state" ], "type": "object" }, "WireguardMeshLinkState": { "description": "How one pair of mesh members is connected.", "enum": [ "direct", "via_hub", "connecting", "unreachable" ], "type": "string" }, "WireguardMeshNodeConnection": { "description": "One node's standing on the mesh, as the control plane sees it.", "enum": [ "mesh_off", "not_registered", "waiting_for_control_plane", "connected", "stale", "never_connected", "unknown" ], "type": "string" }, "WireguardMeshNodeStatus": { "properties": { "checks": { "description": "What the control plane can check about this node's link (empty while\nthe mesh is off). The node's own view: `temps doctor mesh` on it.", "items": { "$ref": "#/components/schemas/WireguardMeshCheck" }, "type": "array" }, "connection": { "$ref": "#/components/schemas/WireguardMeshNodeConnection" }, "data_address": { "description": "Where the control plane reaches this node's agent and published\nports: the mesh address for a node joined over the internet.", "type": "string" }, "endpoint": { "description": "`ip:port` other nodes dial for this node's WireGuard socket.", "type": [ "string", "null" ] }, "last_handshake_at": { "description": "RFC 3339.", "type": [ "string", "null" ] }, "mesh_address": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "node_id": { "format": "int32", "type": "integer" }, "node_status": { "type": "string" }, "registered_address": { "description": "The address the node joined with (`temps join --private-address`).", "type": "string" }, "registered_on_private_network": { "description": "Whether that address is private: the node shares a private network\nwith the control plane rather than only the internet.", "type": "boolean" }, "rx_bytes": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] }, "tx_bytes": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] } }, "required": [ "node_id", "name", "node_status", "registered_address", "registered_on_private_network", "data_address", "connection", "checks" ], "type": "object" }, "WireguardMeshPeerEntry": { "description": "A WireGuard mesh peer on the wire.", "properties": { "address": { "description": "Peer's mesh address (its overlay underlay).", "type": "string" }, "endpoint": { "description": "`ip:port` to dial, or `null` when the peer has none (it dials us).", "type": [ "string", "null" ] }, "name": { "description": "Node name, or `control-plane`. For status output only.", "type": "string" }, "public_key": { "type": "string" }, "relayed": { "description": "On the hub's entry only (ADR 048 D4): the mesh addresses of the\nmembers this node reaches through the hub.", "items": { "type": "string" }, "type": "array" } }, "required": [ "name", "public_key", "address" ], "type": "object" }, "WireguardMeshSelfEntry": { "description": "This node's registered mesh identity, as the control plane stored it.", "properties": { "address": { "type": "string" }, "endpoint": { "type": "string" }, "public_key": { "type": "string" } }, "required": [ "public_key", "endpoint", "address" ], "type": "object" }, "WireguardMeshState": { "description": "Whether the cluster's mesh is carrying traffic.", "enum": [ "disabled", "starting", "ready" ], "type": "string" }, "WireguardMeshStatusResponse": { "description": "Response of `GET /nodes/wireguard`.", "properties": { "can_enable": { "description": "Whether `POST /nodes/wireguard` can turn the mesh on here.", "type": "boolean" }, "cidr": { "description": "Mesh address pool, when enabled.", "type": [ "string", "null" ] }, "control_plane": { "oneOf": [ { "$ref": "#/components/schemas/WireguardMeshControlPlaneEntry" }, { "type": "null" } ] }, "enable_blocker": { "description": "What prevents enabling it, when `can_enable` is false and the mesh is\noff. Rendered verbatim.", "type": [ "string", "null" ] }, "enable_command": { "description": "CLI equivalent of enabling, for the control-plane host.", "type": "string" }, "handshake_error": { "description": "Why handshake data is missing, when it is.", "type": [ "string", "null" ] }, "hub": { "oneOf": [ { "$ref": "#/components/schemas/WireguardMeshHub", "description": "The mesh hub, if one is set." }, { "type": "null" } ] }, "join_url": { "description": "The configured external URL: what `temps join` should point at.\n`null` when none is configured.", "type": [ "string", "null" ] }, "links": { "description": "Every pair of members that are both on the mesh.", "items": { "$ref": "#/components/schemas/WireguardMeshLink" }, "type": "array" }, "listen_port": { "description": "UDP port every node must accept from the others — the configured\none even while the mesh is off, so it can be opened in advance.", "format": "int32", "minimum": 0, "type": "integer" }, "nodes": { "items": { "$ref": "#/components/schemas/WireguardMeshNodeStatus" }, "type": "array" }, "reason": { "description": "Why the mesh is not ready, when it is not. Rendered verbatim.", "type": [ "string", "null" ] }, "state": { "$ref": "#/components/schemas/WireguardMeshState" } }, "required": [ "state", "listen_port", "can_enable", "enable_command", "nodes", "links" ], "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" }, "WorkspaceActivityResponse": { "properties": { "workspaces": { "items": { "$ref": "#/components/schemas/WorkspaceActivitySummary" }, "type": "array" } }, "required": [ "workspaces" ], "type": "object" }, "WorkspaceActivitySummary": { "properties": { "application_public_id": { "description": "Null identifies the user's global workspace.", "type": [ "string", "null" ] }, "harnesses": { "items": { "$ref": "#/components/schemas/WorkspaceHarnessActivity" }, "type": "array" }, "total": { "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "total", "harnesses" ], "type": "object" }, "WorkspaceHarnessActivity": { "properties": { "ai_provider": { "type": "string" }, "cancelled": { "format": "int64", "minimum": 0, "type": "integer" }, "completed": { "format": "int64", "minimum": 0, "type": "integer" }, "failed": { "format": "int64", "minimum": 0, "type": "integer" }, "idle": { "format": "int64", "minimum": 0, "type": "integer" }, "pending": { "format": "int64", "minimum": 0, "type": "integer" }, "running": { "format": "int64", "minimum": 0, "type": "integer" }, "total": { "format": "int64", "minimum": 0, "type": "integer" } }, "required": [ "ai_provider", "total", "pending", "running", "completed", "failed", "cancelled", "idle" ], "type": "object" }, "WriteApplicationWorkspaceFilesRequest": { "additionalProperties": false, "properties": { "files": { "items": { "$ref": "#/components/schemas/ApplicationWorkspaceFileWrite" }, "type": "array" } }, "required": [ "files" ], "type": "object" }, "WriteApplicationWorkspaceFilesResponse": { "properties": { "written": { "minimum": 0, "type": "integer" } }, "required": [ "written" ], "type": "object" }, "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" }, "409": { "description": "Docker daemon unavailable in this profile" }, "500": { "description": "Internal server error" } }, "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", "parameters": [ { "description": "Analytics ingest key (ADR-040), `pa_` followed by 64 hex characters. An alternative to Host-based project resolution, for apps Temps does not deploy and which therefore have no route-table entry. When present it takes precedence and the Host header is not consulted for resolution; a key that does not resolve to an active row is a 401, never a fallback to Host. The value is public by design — it ships in client JS — and is write-only: it grants analytics ingest for one project (optionally one environment) and nothing else.", "in": "header", "name": "x-temps-analytics-key", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Query-string fallback for the analytics ingest key, for clients that cannot set custom headers (`navigator.sendBeacon`, used for page-unload events). Consulted only when the `x-temps-analytics-key` header is absent; identical precedence and error semantics.", "in": "query", "name": "temps_key", "required": false, "schema": { "type": "string" } } ], "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/sentry/envelope": { "post": { "description": "Two resolution paths, tried in this order:\n\n1. **DSN credential.** An explicit `?sentry_key=` / `X-Sentry-Auth` /\n `Authorization: DSN` value, or — failing that — the `dsn` field browser\n SDKs embed in the envelope header whenever `Sentry.init({ tunnel })` is\n used. The credential alone decides the project; `Host` and `Origin` are\n not consulted. This is what makes the endpoint usable from an app Temps\n does not deploy, which by definition has no route-table entry at all.\n2. **`Host`.** Unchanged legacy behaviour for same-origin, Temps-deployed\n apps: the project/environment/deployment are resolved from the `Host`\n header via the proxy's route table, the same way `/api/_temps/event`\n (analytics) resolves. The proxy forwards anything under `/api/_temps`\n to the console regardless of `Host`\n (`temps-proxy::services::ROUTE_PREFIX_TEMPS`), so it works on custom\n domains and previews without per-domain DSN configuration.\n\nOn path 2 there is no credential, so an `Origin`/`Referer` check stands in\nfor authentication: the request must claim to come from the same host it\nresolves to, or it is rejected. That check is deliberately **skipped** on\npath 1 — a tunneled request from another origin is the entire point there,\nand the DSN is a stronger claim than a self-reported `Origin`. Path 1 does\nhonour the DSN row's own `allowed_origins` list when the operator has set\none (`403` when the `Origin` is off it); an empty or absent list, which is\nevery row Temps mints today, permits any origin.\n\n# Ordering, and why it matters\n\nThis route is unauthenticated and reachable from every domain a project is\ndeployed to, so the expensive work is placed strictly after the cheap\nadmission control:\n\n1. Shape gate + resolution cache + a global unresolved-credential budget,\n all before any database round trip (mirroring `temps-analytics`'s\n ADR-040 §2 defence).\n2. Per-project rate limiting.\n3. Only then `decompress_if_needed`, which can inflate up to\n `MAX_DECOMPRESSED_SIZE`.\n\nThe credential-free branch has to inflate the body to read an SDK-embedded\nDSN, so when `Host` has not already resolved the request that inflate is\ncharged against the same global budget a forged key pays into.\n\nAn *explicit* credential that does not resolve is a `401`, never a silent\nfall-through to `Host`: a typo'd key must fail loudly rather than land the\ndata under whichever project the `Host` happens to match. An *embedded*\nenvelope DSN that does not resolve falls through to path 2, because that\nvalue was sniffed rather than presented — an app tunneling a third-party\nDSN through Temps keeps working exactly as it did before.", "operationId": "ingest_tunneled_envelope", "parameters": [ { "description": "DSN public key; resolves the project without consulting Host", "in": "query", "name": "sentry_key", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/octet-stream": { "schema": { "type": "string" } } }, "description": "Sentry envelope as binary data", "required": true }, "responses": { "200": { "description": "Envelope ingested" }, "204": { "description": "Host resolved to a route with no attributable project (sandbox/orphan)" }, "400": { "description": "Bad request" }, "401": { "description": "An explicit DSN key was presented but did not resolve" }, "403": { "description": "Origin/Referer does not match the resolved host (Host-resolved requests), or the Origin is not in the DSN's allowed_origins (keyed requests)" }, "404": { "description": "Unknown host" }, "413": { "description": "Request body too large (exceeds 2 MiB)" }, "429": { "description": "Rate limit exceeded" } }, "summary": "Ingest a browser-tunneled Sentry envelope.", "tags": [ "sentry-ingestor" ] } }, "/_temps/session-replay/events": { "post": { "operationId": "add_session_replay_events", "parameters": [ { "description": "Analytics ingest key (ADR-040), `pa_` followed by 64 hex characters. An alternative to Host-based project resolution, for apps Temps does not deploy and which therefore have no route-table entry. When present it takes precedence and the Host header is not consulted for resolution; a key that does not resolve to an active row is a 401, never a fallback to Host. The value is public by design — it ships in client JS — and is write-only: it grants analytics ingest for one project (optionally one environment) and nothing else.", "in": "header", "name": "x-temps-analytics-key", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Query-string fallback for the analytics ingest key, for clients that cannot set custom headers (`navigator.sendBeacon`, used to flush the final replay batch on page unload). Consulted only when the `x-temps-analytics-key` header is absent; identical precedence and error semantics.", "in": "query", "name": "temps_key", "required": false, "schema": { "type": "string" } } ], "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" ], "x-maturity": "beta" } }, "/_temps/session-replay/init": { "post": { "operationId": "init_session_replay", "parameters": [ { "description": "Analytics ingest key (ADR-040), `pa_` followed by 64 hex characters. An alternative to Host-based project resolution, for apps Temps does not deploy and which therefore have no route-table entry. When present it takes precedence and the Host header is not consulted for resolution; a key that does not resolve to an active row is a 401, never a fallback to Host. The value is public by design — it ships in client JS — and is write-only: it grants analytics ingest for one project (optionally one environment) and nothing else.", "in": "header", "name": "x-temps-analytics-key", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Query-string fallback for the analytics ingest key, for clients that cannot set custom headers (`navigator.sendBeacon`). Consulted only when the `x-temps-analytics-key` header is absent; identical precedence and error semantics.", "in": "query", "name": "temps_key", "required": false, "schema": { "type": "string" } } ], "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" ], "x-maturity": "beta" } }, "/_temps/speed": { "post": { "operationId": "record_speed_metrics", "parameters": [ { "description": "Analytics ingest key (ADR-040), `pa_` followed by 64 hex characters. An alternative to Host-based project resolution, for apps Temps does not deploy and which therefore have no route-table entry. When present it takes precedence and the Host header is not consulted for resolution; a key that does not resolve to an active row is a 401, never a fallback to Host. The value is public by design — it ships in client JS — and is write-only: it grants analytics ingest for one project (optionally one environment) and nothing else.", "in": "header", "name": "x-temps-analytics-key", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Query-string fallback for the analytics ingest key, for clients that cannot set custom headers (`navigator.sendBeacon`, used for page-unload events). Consulted only when the `x-temps-analytics-key` header is absent; identical precedence and error semantics.", "in": "query", "name": "temps_key", "required": false, "schema": { "type": "string" } } ], "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", "parameters": [ { "description": "Analytics ingest key (ADR-040), `pa_` followed by 64 hex characters. An alternative to Host-based project resolution, for apps Temps does not deploy and which therefore have no route-table entry. When present it takes precedence and the Host header is not consulted for resolution; a key that does not resolve to an active row is a 401, never a fallback to Host. The value is public by design — it ships in client JS — and is write-only: it grants analytics ingest for one project (optionally one environment) and nothing else.", "in": "header", "name": "x-temps-analytics-key", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Query-string fallback for the analytics ingest key, for clients that cannot set custom headers. This endpoint is called via `navigator.sendBeacon` on page unload, so the query form is the only one available there. Consulted only when the `x-temps-analytics-key` header is absent; identical precedence and error semantics.", "in": "query", "name": "temps_key", "required": false, "schema": { "type": "string" } } ], "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" ], "x-maturity": "experimental" } }, "/ai/applications": { "get": { "operationId": "list_applications", "parameters": [ { "description": "Resource lifecycle state (defaults to active).", "in": "query", "name": "status", "required": false, "schema": { "$ref": "#/components/schemas/ConversationListStatus" } }, { "description": "Page number (1-indexed).", "example": 1, "in": "query", "name": "page", "required": false, "schema": { "format": "int64", "minimum": 1, "type": "integer" } }, { "description": "Number of applications or conversations per page (clamped to 1..=100).", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "maximum": 100, "minimum": 1, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ApplicationResponse" }, "type": "array" } } } }, "401": {}, "403": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" }, "post": { "operationId": "create_application", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateApplicationRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationResponse" } } } }, "400": {}, "401": {}, "403": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}": { "delete": { "description": "Archives the application and pauses its workspace compute while retaining projects, conversations, and persistent files.", "operationId": "archive_application", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "204": {}, "401": {}, "403": {}, "404": {}, "503": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Archive an AI application", "tags": [ "AI Applications" ], "x-maturity": "experimental" }, "get": { "operationId": "get_application", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "description": "Resource lifecycle state (defaults to active).", "in": "query", "name": "status", "required": false, "schema": { "$ref": "#/components/schemas/ConversationListStatus" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationResponse" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/conversations": { "get": { "operationId": "list_application_conversations", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "description": "Resource lifecycle state (defaults to active).", "in": "query", "name": "status", "required": false, "schema": { "$ref": "#/components/schemas/ConversationListStatus" } }, { "description": "Page number (1-indexed).", "example": 1, "in": "query", "name": "page", "required": false, "schema": { "format": "int64", "minimum": 1, "type": "integer" } }, { "description": "Number of applications or conversations per page (clamped to 1..=100).", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "maximum": 100, "minimum": 1, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ConversationResponse" }, "type": "array" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" }, "post": { "operationId": "create_application_conversation", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateApplicationConversationRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConversationResponse" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/conversations/{conversation_public_id}/artifacts": { "get": { "operationId": "list_thread_artifacts", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "conversation_public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ThreadArtifactResponse" }, "type": "array" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" }, "post": { "operationId": "create_thread_artifact", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "conversation_public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateThreadArtifactRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ThreadArtifactResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/git-connections": { "get": { "operationId": "listApplicationGitConnections", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationGitConnectionsResponse" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" }, "post": { "operationId": "bindApplicationGitConnection", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BindApplicationGitConnectionRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GitBindingResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/git-connections/{binding_id}": { "delete": { "operationId": "disconnectApplicationGitConnection", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "binding_id", "required": true, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "204": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/preview-link": { "post": { "operationId": "create_application_preview_link", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateApplicationPreviewLinkRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationPreviewLinkResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "503": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Mint a short-lived URL for a port running in the application harness\nsandbox. This intentionally does not return the bare `ws-…` hostname:\napplication sandboxes always have a private preview password and only the\ngateway can exchange this grant for the preview cookie.", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/projects": { "post": { "description": "Creates a Temps project, links it to the user-owned application, creates projects/ in its persistent workspace, and refreshes the application topology in one approval-gated server workflow.", "operationId": "create_application_project", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateApplicationProjectRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Create and link an application project", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/projects/link": { "post": { "operationId": "link_application_project", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LinkApplicationProjectRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationResponse" } } } }, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Link an existing project to an application", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/projects/{project_id}": { "delete": { "description": "Unlinks a project and its data-network access. A workspace may contain no linked projects.", "operationId": "unlink_application_project", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationResponse" } } } }, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Unlink an application project", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/projects/{project_id}/deploy": { "post": { "description": "Packages projects/ from the application's persistent workspace and starts the existing Temps uploaded-source Drop workflow. The operation is exposed to chat through temps_write and therefore follows the active native approval mode.", "operationId": "deploy_application_workspace_project", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeployApplicationProjectRequest" } } }, "required": true }, "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationProjectDeploymentResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "409": {}, "413": {}, "503": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Deploy an application workspace project with Drop", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/projects/{project_id}/primary": { "post": { "operationId": "set_application_primary_project", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationResponse" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Choose the application's primary project", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/projects/{project_id}/workspace/files": { "post": { "description": "Re-authorizes every linked project and writes a configured, bounded batch of project-relative files into the selected persistent workspace directory.", "operationId": "write_application_workspace_files", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WriteApplicationWorkspaceFilesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WriteApplicationWorkspaceFilesResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Write a bounded batch of local files into an application project", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/projects/{project_id}/workspace/source": { "post": { "description": "Re-authorizes every linked project, resolves an optional user-owned Git connection server-side, and shallow-clones into the selected project directory.", "operationId": "import_application_workspace_git", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportApplicationWorkspaceGitRequest" } } }, "required": true }, "responses": { "204": {}, "400": {}, "401": {}, "403": {}, "404": {}, "409": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Import a Git repository into an application project", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/restore": { "post": { "description": "Restores an archived application and requests that its retained persistent workspace resume on next access.", "operationId": "restore_application", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationResponse" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Restore an archived AI application", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/workspace": { "get": { "operationId": "get_application_workspace", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceResponse" } } } }, "401": {}, "403": {}, "404": {}, "503": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" }, "patch": { "description": "Persists desired runtime and resource settings server-side, then replaces compute while retaining the application files.", "operationId": "update_application_workspace", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateApplicationWorkspaceRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Update desired application workspace resources", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/workspace/actions": { "post": { "description": "Restart, pause, resume, rebuild, snapshot, or restore the application's persistent workspace. Files outlive suspended or replaced compute.", "operationId": "control_application_workspace", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ControlApplicationWorkspaceRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Control an application workspace", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/workspace/changes": { "get": { "operationId": "get_application_workspace_changes", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "description": "Position returned by the previous page", "in": "query", "name": "cursor", "required": false, "schema": { "minimum": 0, "type": "integer" } }, { "description": "Files per page (1-200, default 100)", "in": "query", "name": "limit", "required": false, "schema": { "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceChangesResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "503": {}, "504": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/workspace/diff": { "get": { "operationId": "get_application_workspace_diff", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "query", "name": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceDiffResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "413": {}, "503": {}, "504": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/workspace/directory": { "get": { "operationId": "get_application_workspace_directory", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "description": "Workspace-relative directory; omit for the root", "in": "query", "name": "path", "required": false, "schema": { "type": "string" } }, { "description": "Position returned by the previous page", "in": "query", "name": "cursor", "required": false, "schema": { "minimum": 0, "type": "integer" } }, { "description": "Entries per page (1-100, default 100)", "in": "query", "name": "limit", "required": false, "schema": { "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceDirectoryResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/workspace/file": { "get": { "operationId": "get_application_workspace_file", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "query", "name": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceFileContentResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/workspace/file/download": { "get": { "operationId": "download_application_workspace_file", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } }, { "in": "query", "name": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/octet-stream": { "schema": { "items": { "format": "int32", "minimum": 0, "type": "integer" }, "type": "array" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "413": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Download one application workspace file", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/applications/{application_public_id}/workspace/files": { "post": { "description": "Writes a configured, bounded batch of safe workspace-relative files into the persistent workspace without waking compute.", "operationId": "upload_application_workspace_files", "parameters": [ { "in": "path", "name": "application_public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WriteApplicationWorkspaceFilesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WriteApplicationWorkspaceFilesResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "413": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Upload files into an application workspace", "tags": [ "AI Applications" ], "x-maturity": "experimental" } }, "/ai/conversations": { "get": { "operationId": "list_all_conversations", "parameters": [ { "description": "Conversation lifecycle state (defaults to active).", "in": "query", "name": "status", "required": false, "schema": { "$ref": "#/components/schemas/ConversationListStatus" } }, { "description": "Limit results to the global workspace, or return every readable context.", "in": "query", "name": "scope", "required": false, "schema": { "$ref": "#/components/schemas/ConversationListScope" } }, { "description": "Page number (1-indexed).", "example": 1, "in": "query", "name": "page", "required": false, "schema": { "format": "int64", "minimum": 1, "type": "integer" } }, { "description": "Number of conversations per page (clamped to 1..=100).", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "maximum": 100, "minimum": 1, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/GlobalConversationResponse" }, "type": "array" } } } }, "401": {}, "403": {} }, "security": [ { "bearer_auth": [] } ], "summary": "List the current user's active conversations across all projects,\nmost-recently-active first, annotated with project name/slug.", "tags": [ "AI Chat" ], "x-maturity": "experimental" }, "post": { "operationId": "create_global_conversation", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateGlobalConversationRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConversationResponse" } } } }, "400": {}, "401": {}, "403": {}, "409": {}, "503": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Create a private user-owned operator thread without binding its lifetime or\nauthority to a project. Project access is selected per tool call and checked\nagainst the user's current role and memberships.", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}": { "get": { "operationId": "get_user_conversation", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } }, { "description": "Opaque next_before cursor returned by the previous page", "in": "query", "name": "before", "required": false, "schema": { "type": "string" } }, { "description": "Messages per page (default 50, maximum 100)", "in": "query", "name": "limit", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConversationDetailResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Load one bounded history page for a private conversation by its owner-facing\nid. Project/application context is revalidated, but never used as the\nownership key.", "tags": [ "AI Chat" ], "x-maturity": "experimental" }, "patch": { "operationId": "rename_user_conversation", "parameters": [ { "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" } } } }, "400": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/archive": { "post": { "operationId": "archive_user_conversation", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "204": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/attachments": { "post": { "operationId": "upload_user_conversation_attachment", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/ChatAttachmentUpload" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatAttachmentResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "413": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/attachments/{attachment_id}": { "get": { "operationId": "get_user_conversation_attachment", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "attachment_id", "required": true, "schema": { "type": "string" } }, { "in": "query", "name": "name", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/octet-stream": { "schema": { "items": { "format": "int32", "minimum": 0, "type": "integer" }, "type": "array" } } } }, "400": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/diagnostics": { "get": { "operationId": "getUserConversationDiagnostics", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } }, { "description": "Persisted rows to include, newest window first (default/max 25).", "in": "query", "name": "limit", "required": false, "schema": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConversationDiagnosticResponse" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Export the bounded, server-redacted diagnostic state Temps currently owns.", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/messages": { "post": { "operationId": "send_user_message", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendMessageRequest" } } }, "required": true }, "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendMessageAcceptedResponse" } } } }, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Submit a turn to a user-owned conversation. The authenticated user's\ncurrent role and permissions are captured for this turn's tool executor;\nno project id from the browser is trusted or required.", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/pending-actions": { "get": { "operationId": "list_user_pending_actions", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/PendingActionResponse" }, "type": "array" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/permission-mode": { "post": { "operationId": "update_user_permission_mode", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdatePermissionModeRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConversationResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/permissions/{permission_id}/resolve": { "post": { "operationId": "resolve_user_permission", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "permission_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResolvePermissionRequest" } } }, "required": true }, "responses": { "204": {}, "400": {}, "401": {}, "403": {}, "404": {}, "409": {}, "410": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/restore": { "post": { "operationId": "restore_user_conversation", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "204": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Restore a user-owned archived conversation.", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/conversations/{public_id}/stop": { "post": { "operationId": "stop_user_turn", "parameters": [ { "in": "path", "name": "public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "204": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/pending-actions/{action_public_id}": { "get": { "operationId": "get_user_pending_action", "parameters": [ { "in": "path", "name": "action_public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PendingActionResponse" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/pending-actions/{action_public_id}/confirm": { "post": { "operationId": "confirm_user_pending_action", "parameters": [ { "in": "path", "name": "action_public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PendingActionResponse" } } } }, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/pending-actions/{action_public_id}/reject": { "post": { "operationId": "reject_user_pending_action", "parameters": [ { "in": "path", "name": "action_public_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PendingActionResponse" } } } }, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/preview/authorize": { "post": { "operationId": "authorize_workspace_preview", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthorizeWorkspacePreviewRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationPreviewLinkResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "503": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Renew a managed preview only for an already-bound, running workspace. The\nrequested sandbox ID is an object selector, never an authorization grant.", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/ai/provider-status": { "get": { "operationId": "get_ai_provider_status", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AiProviderStatusResponse" } } }, "description": "Current provider preference and availability" }, "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": [ "AI Provider Status" ], "x-maturity": "experimental" } }, "/ai/provider-status/refresh": { "post": { "operationId": "refresh_ai_provider_status", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AiProviderStatusResponse" } } }, "description": "Fresh provider authentication and model capability snapshot" }, "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": "Provider refresh failed" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Provider Status" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" }, "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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" }, "get": { "operationId": "get_provider_key", "parameters": [ { "description": "Provider key ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderDetailResponse" } } } }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway Admin" ], "x-maturity": "experimental" }, "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" ], "x-maturity": "experimental" } }, "/ai/providers/{id}/models": { "post": { "operationId": "add_provider_model", "parameters": [ { "description": "Provider key ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddProviderModelRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderModelResponse" } } } }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway Admin" ], "x-maturity": "experimental" } }, "/ai/providers/{id}/models/refresh": { "post": { "operationId": "refresh_provider_models", "parameters": [ { "description": "Provider key ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ProviderModelResponse" }, "type": "array" } } } }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway Admin" ], "x-maturity": "experimental" } }, "/ai/providers/{id}/models/{model_row_id}": { "delete": { "operationId": "delete_provider_model", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "in": "path", "name": "model_row_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "204": {}, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway Admin" ], "x-maturity": "experimental" }, "patch": { "operationId": "update_provider_model", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "in": "path", "name": "model_row_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateProviderModelRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderModelResponse" } } } }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway Admin" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/ai/summary-preference": { "put": { "operationId": "update_ai_summary_preference", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateAiSummaryPreferenceRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AiProviderStatusResponse" } } }, "description": "Updated summary routing defaults" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unsupported provider, model, or thinking level" }, "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 Provider Status" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/ai/v1/batches": { "post": { "operationId": "create_batch", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateBatchRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchObject" } } }, "description": "Batch created" }, "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": "Input file not found for the caller" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway" ], "x-maturity": "experimental" } }, "/ai/v1/batches/{batch_id}": { "get": { "operationId": "retrieve_batch", "parameters": [ { "description": "Provider batch id, e.g. batch_abc123", "in": "path", "name": "batch_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchObject" } } }, "description": "Batch object" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Unauthorized" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "No such batch created by the caller" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway" ], "x-maturity": "experimental" } }, "/ai/v1/batches/{batch_id}/cancel": { "post": { "operationId": "cancel_batch", "parameters": [ { "description": "Provider batch id, e.g. batch_abc123", "in": "path", "name": "batch_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchObject" } } }, "description": "Batch is cancelling" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Unauthorized" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "No such batch created by the caller" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/ai/v1/files": { "post": { "operationId": "upload_file", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/UploadFileForm" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FileObject" } } }, "description": "Uploaded file" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Invalid batch input file" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Model not allowed" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Model or provider not configured" }, "413": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "File larger than 200 MB" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Concurrent upload capacity reached; retry later" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway" ], "x-maturity": "experimental" } }, "/ai/v1/files/{file_id}": { "delete": { "operationId": "delete_file", "parameters": [ { "description": "Provider file id, e.g. file-abc123", "in": "path", "name": "file_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FileDeletedResponse" } } }, "description": "File deleted" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Unauthorized" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "No such file created by the caller" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway" ], "x-maturity": "experimental" }, "get": { "operationId": "retrieve_file", "parameters": [ { "description": "Provider file id, e.g. file-abc123", "in": "path", "name": "file_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FileObject" } } }, "description": "File object" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Unauthorized" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "No such file created by the caller" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway" ], "x-maturity": "experimental" } }, "/ai/v1/files/{file_id}/content": { "get": { "operationId": "file_content", "parameters": [ { "description": "Provider file id, e.g. a batch's output_file_id", "in": "path", "name": "file_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/octet-stream": {} }, "description": "File content (JSONL for batch files), streamed" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Unauthorized" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "No such file created by the caller" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/ai/v1/responses": { "post": { "operationId": "create_response", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResponsesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResponseObject" } }, "text/event-stream": { "schema": { "$ref": "#/components/schemas/ResponseStreamEvent" } } }, "description": "JSON when stream=false, SSE when stream=true. Generated SDKs use the explicit /json and /stream operations." }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Invalid request, or the model is not served by OpenAI" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Model not allowed" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Model or provider not configured" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway" ], "x-maturity": "experimental" } }, "/ai/v1/responses/json": { "post": { "operationId": "create_response_json", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResponsesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResponseObject" } } }, "description": "Complete response object; forces stream=false" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Invalid request" } }, "security": [ { "bearer_auth": [] } ], "summary": "Explicit JSON contract for generated clients; the standard OpenAI route remains polymorphic.", "tags": [ "AI Gateway" ], "x-maturity": "experimental" } }, "/ai/v1/responses/stream": { "post": { "operationId": "create_response_stream", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResponsesRequest" } } }, "required": true }, "responses": { "200": { "content": { "text/event-stream": { "schema": { "$ref": "#/components/schemas/ResponseStreamEvent" } } }, "description": "Incremental Responses events; forces stream=true" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenAiErrorResponse" } } }, "description": "Invalid request" } }, "security": [ { "bearer_auth": [] } ], "summary": "Explicit SSE contract for generated clients; never buffers a successful event stream.", "tags": [ "AI Gateway" ], "x-maturity": "experimental" } }, "/ai/workspace": { "get": { "operationId": "get_global_ai_workspace", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceResponse" } } } }, "401": {}, "403": {}, "503": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/workspace-activity": { "get": { "operationId": "get_workspace_activity", "parameters": [ { "description": "Comma-separated application public IDs (maximum 100). Omit for the global workspace only.", "in": "query", "name": "application_public_ids", "required": false, "schema": { "type": [ "string", "null" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkspaceActivityResponse" } } } }, "400": {}, "401": {}, "403": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Aggregate all active threads for the caller's global workspace and up to\n100 requested, visible application workspaces. Thread history is not paged.", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/workspace/changes": { "get": { "operationId": "get_global_workspace_changes", "parameters": [ { "description": "Position returned by the previous page", "in": "query", "name": "cursor", "required": false, "schema": { "minimum": 0, "type": "integer" } }, { "description": "Files per page (1-200, default 100)", "in": "query", "name": "limit", "required": false, "schema": { "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceChangesResponse" } } } }, "400": {}, "401": {}, "403": {}, "503": {}, "504": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/workspace/diff": { "get": { "operationId": "get_global_workspace_diff", "parameters": [ { "in": "query", "name": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceDiffResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "413": {}, "503": {}, "504": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/workspace/directory": { "get": { "operationId": "get_global_workspace_directory", "parameters": [ { "description": "Workspace-relative directory; omit for the root", "in": "query", "name": "path", "required": false, "schema": { "type": "string" } }, { "description": "Position returned by the previous page", "in": "query", "name": "cursor", "required": false, "schema": { "minimum": 0, "type": "integer" } }, { "description": "Entries per page (1-100, default 100)", "in": "query", "name": "limit", "required": false, "schema": { "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceDirectoryResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/workspace/file": { "get": { "operationId": "get_global_workspace_file", "parameters": [ { "in": "query", "name": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationWorkspaceFileContentResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/workspace/file-limits": { "get": { "description": "Returns the non-sensitive effective transfer and preview policy for the current workspace user.", "operationId": "get_workspace_file_limits", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AiWorkspaceFileLimitsSettings" } } } }, "401": {}, "403": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Get effective AI workspace file limits", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/workspace/file/download": { "get": { "operationId": "download_global_workspace_file", "parameters": [ { "in": "query", "name": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/octet-stream": { "schema": { "items": { "format": "int32", "minimum": 0, "type": "integer" }, "type": "array" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "413": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Download one global AI workspace file", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/workspace/files": { "post": { "description": "Writes a configured, bounded batch of safe workspace-relative files into the user's persistent global workspace without waking compute.", "operationId": "upload_global_workspace_files", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WriteApplicationWorkspaceFilesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WriteApplicationWorkspaceFilesResponse" } } } }, "400": {}, "401": {}, "403": {}, "413": {}, "500": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Upload files into the global AI workspace", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/ai/workspace/preview-link": { "post": { "operationId": "create_global_workspace_preview_link", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateApplicationPreviewLinkRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationPreviewLinkResponse" } } } }, "400": {}, "401": {}, "403": {}, "503": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Mint a short-lived preview URL for a port in the user's shared global AI\nworkspace. The gateway grant is identical to application previews; the\nonly difference is how the owning sandbox is resolved.", "tags": [ "AI Chat" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/analytics/global": { "get": { "operationId": "get_global_analytics", "parameters": [ { "in": "query", "name": "facet", "required": false, "schema": { "oneOf": [ { "$ref": "#/components/schemas/AnalyticsFacet" }, { "type": "null" } ] } }, { "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "in": "query", "name": "environment_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "in": "query", "name": "start_date", "required": true, "schema": { "format": "date-time", "type": "string" } }, { "in": "query", "name": "end_date", "required": true, "schema": { "format": "date-time", "type": "string" } }, { "in": "query", "name": "search", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "dimension", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "device", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "page", "required": false, "schema": { "format": "int32", "minimum": 0, "type": [ "integer", "null" ] } }, { "in": "query", "name": "per_page", "required": false, "schema": { "format": "int32", "minimum": 0, "type": [ "integer", "null" ] } }, { "in": "query", "name": "min_views", "required": false, "schema": { "format": "int32", "minimum": 0, "type": [ "integer", "null" ] } }, { "in": "query", "name": "min_sessions", "required": false, "schema": { "format": "int32", "minimum": 0, "type": [ "integer", "null" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalAnalyticsResponse" } } } }, "400": { "description": "Invalid analytics filters" }, "403": { "description": "Access denied" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Analytics" ], "x-maturity": "beta" } }, "/analytics/global/projects": { "get": { "operationId": "get_analytics_projects", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/AnalyticsProjectOption" }, "type": "array" } } } }, "403": { "description": "Access denied" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Analytics" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/analytics/visitors/{visitor_id}/enrich": { "put": { "description": "The top-level keys of `custom_data` are merged into what is already stored;\na key set to `null` is removed. A deployed app can call this with its\ninjected deployment token (permission `visitors:enrich`), using the sealed\n`enc_…` value of the `_temps_visitor_id` cookie, for visitors of its own\nproject only.", "operationId": "enrich_visitor", "parameters": [ { "description": "Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx). Deployment tokens (visitors:enrich) may only use the encrypted GUID and only for visitors of their own project.", "in": "path", "name": "visitor_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EnrichVisitorRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EnrichVisitorResponse" } } }, "description": "Enrichment result. `success: false` means the visitor was not found (or is not in the caller's project) and nothing was changed." }, "400": { "description": "Invalid visitor ID, or enrichment data that is not a JSON object within the size limits" }, "403": { "description": "Deployment token used with a non-encrypted visitor ID" }, "429": { "description": "The deployment token made too many visitor-changing enrichments in the last minute; retry shortly" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Attach attributes (for example the signed-in user's id, name and email) to a\nvisitor.", "tags": [ "Analytics" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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/cloud/login": { "get": { "description": "The slug embeds the provider's row id, which Cloud does not know and the\ninstance may regenerate, so Cloud's \"Open console\" button needs a fixed\naddress it can link to: this one. A browser that already holds a Cloud\nsession completes the round trip without seeing a login page, which is\nwhat makes the hosted console feel signed-in from Cloud. Anything else\n(the interactive login, the callback, `return_to` sanitising) is exactly\nthe slug route; only the lookup differs. 404 when no managed provider is\ninstalled, so a self-hosted instance that never enrolled has nothing to\nprobe here.", "operationId": "start_managed_cloud_login", "parameters": [ { "in": "query", "name": "return_to", "required": false, "schema": { "type": [ "string", "null" ] } } ], "responses": { "302": { "description": "Redirect to the Temps Cloud authorize URL" }, "404": { "description": "This instance has no Cloud-managed console-access provider" }, "503": { "description": "OIDC provider unreachable" } }, "summary": "Start a login against the Cloud-managed console-access provider without\nknowing its slug.", "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-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", "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" }, "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 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}/capability": { "get": { "description": "This probes the running container instead of trusting its configured image\nname: operators can build their own WAL-G image, and an image label alone\ncannot prove that the binary is actually executable.", "operationId": "get_external_service_backup_capability", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExternalServiceBackupCapabilityResponse" } } }, "description": "Cloud backup compatibility" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "External service not found" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Capability could not be loaded" } }, "security": [ { "bearer_auth": [] } ], "summary": "Report whether an existing service can produce a Cloud-restorable backup.", "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" }, "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": "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" }, "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 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" }, "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 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" }, "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 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" }, "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": "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" }, "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": "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" }, "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": "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" }, "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": "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" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "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": "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" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "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 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" }, "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 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" }, "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 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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "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": "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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "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": "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" } }, { "description": "Project ID (required for API key/session auth, optional for deployment tokens)", "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": "integer" } } ], "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", "parameters": [ { "description": "Path where the blob will be stored", "in": "query", "name": "pathname", "required": false, "schema": { "type": "string" } }, { "description": "Content type of the blob (optional, will be guessed from extension)", "in": "query", "name": "content_type", "required": false, "schema": { "type": "string" } }, { "description": "Add random suffix to pathname to prevent collisions", "in": "query", "name": "add_random_suffix", "required": false, "schema": { "type": "boolean" } }, { "description": "Project ID (required for API key/session auth, optional for deployment tokens)", "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": "integer" } } ], "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" ] } }, "/cloud": { "delete": { "operationId": "disconnect_cloud", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloudStatus" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Cloud" ] } }, "/cloud/ai/capability": { "get": { "operationId": "get_cloud_ai_capability", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloudAiCapability" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Cloud" ] } }, "/cloud/backups/schedule/ensure": { "post": { "operationId": "ensure_cloud_backup_schedule", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ManagedBackupSetup" } } }, "description": "The managed destination's setup with the schedule that targets it, created when none did" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Authentication required" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "No schedule could be set up; the detail says why (Cloud did not answer the plan's retention, the backup plugin is not enabled)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Database or link state failure" } }, "security": [ { "bearer_auth": [] } ], "summary": "Create the nightly schedule for the Temps Cloud destination unless one\nalready targets it (ADR-044). Answers the same shape as the reconcile so\nthe console can swap it into the status it already holds.", "tags": [ "Cloud" ] } }, "/cloud/backups/source/reconcile": { "post": { "operationId": "reconcile_cloud_backup_source", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ManagedBackupSetup" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Cloud" ] } }, "/cloud/capability": { "get": { "operationId": "get_cloud_capability", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloudCapability" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Cloud" ] } }, "/cloud/enroll": { "post": { "operationId": "enroll_cloud", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EnrollCloudRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloudStatus" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Cloud" ] } }, "/cloud/features": { "patch": { "operationId": "update_cloud_features", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloudFeatureSwitchesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloudStatus" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Cloud" ] } }, "/cloud/status": { "get": { "operationId": "get_cloud_status", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloudStatus" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Cloud" ] } }, "/cluster/dns/status": { "get": { "description": "Same permission as the other node visibility endpoints in this file\n(`admin_list_nodes`, `admin_get_node`) — this is operational/infra\nvisibility, not a new privilege tier.", "operationId": "cluster_dns_status", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClusterDnsStatusResponse" } } }, "description": "Cluster DNS resolver health" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Cluster-wide DNS resolver health (ADR-024): whether cluster DNS is\nenabled, the total record count, and per-node resolver status as last\nreported by each node's heartbeat. Lets an operator answer \"is cluster\nDNS actually healthy right now\" without SSHing into a node to read logs.", "tags": [ "Nodes" ] } }, "/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" ], "x-maturity": "beta" } }, "/delivery-capabilities": { "get": { "operationId": "get_delivery_capabilities", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/DeliveryCapabilityResponse" }, "type": "array" } } }, "description": "Supported delivery providers and their setup state" }, "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": [ "Traffic Delivery" ] } }, "/delivery-profiles": { "get": { "description": "Newest first by default. `sort_by` accepts `created_at` (default) or\n`name`; `sort_order` accepts `asc` or `desc` (default), case-insensitive.\nProfile ID breaks ties in the same direction. `page_size` defaults to 20\nand is clamped to 1..=100. `search` keeps only profiles whose name\ncontains it, ignoring case, and combines with paging and sorting: `total`\ncounts the matching profiles.\n\nCallers with DNS provider read access see every field. Project readers\nwithout it (who need profiles for the project delivery switch) get a\nreduced view: `id`, `name`, `provider_kind` and timestamps, with\n`bunny_pull_zone_id` and `bunny_hostname` set to `null`.", "operationId": "list_delivery_profiles", "parameters": [ { "description": "Page number (1-indexed)", "example": 1, "in": "query", "name": "page", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "description": "Number of items per page (max 100)", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": "string" } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": "string" } }, { "description": "Keep only profiles whose name contains this text, ignoring case.\nSurrounding whitespace is ignored and a blank value matches every\nprofile; `%`, `_` and `\\` match themselves. At most 100 characters.", "example": "edge", "in": "query", "name": "search", "required": false, "schema": { "maxLength": 100, "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeliveryProfilePage" } } }, "description": "One page of delivery profiles; provider details are null without DNS provider read access" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unknown sort_by or sort_order value, or a search term longer than 100 characters" }, "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 delivery profiles, one page at a time.", "tags": [ "Traffic Delivery" ] }, "post": { "operationId": "create_delivery_profile", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateDeliveryProfileRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeliveryProfileResponse" } } }, "description": "Delivery profile created" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Invalid profile or Bunny Pull Zone configuration" }, "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": "A profile with this name already exists" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Bunny API rate limited the request" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" }, "502": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Bunny API unreachable or returned an error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Traffic Delivery" ] } }, "/delivery-profiles/{profile_id}": { "delete": { "operationId": "delete_delivery_profile", "parameters": [ { "description": "Delivery profile ID", "in": "path", "name": "profile_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "204": { "description": "Delivery profile 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": "Delivery profile not found" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Profile is still referenced or required by the new-project default" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Traffic Delivery" ] }, "get": { "description": "Same visibility as `GET /delivery-profiles`: callers with DNS provider\nread access see every field, project readers get the reduced view.", "operationId": "get_delivery_profile", "parameters": [ { "description": "Delivery profile ID", "in": "path", "name": "profile_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeliveryProfileResponse" } } }, "description": "Delivery profile; provider details are null without DNS provider read access" }, "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": "Delivery profile not found" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Get one delivery profile.", "tags": [ "Traffic Delivery" ] } }, "/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" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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/latest-media": { "get": { "operationId": "get_latest_deployment_media", "parameters": [ { "description": "Comma-separated project IDs. At most 100 IDs are accepted.", "in": "query", "name": "project_ids", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LatestDeploymentMediaResponse" } } }, "description": "Latest deployment media keyed by project ID" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Invalid project IDs" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permission or project access" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Get the latest deployment URL and screenshot location for multiple projects.", "tags": [ "Deployments" ] } }, "/deployments/managed-environment-variables": { "get": { "operationId": "list_managed_environment_variables", "parameters": [ { "description": "Framework preset used to select public browser variable names.", "in": "query", "name": "preset", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ManagedEnvironmentVariable" }, "type": "array" } } }, "description": "Platform-managed environment variable metadata" }, "400": { "description": "Unknown deployment preset" }, "401": { "description": "Authentication required" }, "403": { "description": "Missing project creation permission" } }, "security": [ { "bearer_auth": [] } ], "summary": "List the environment variables generated by Temps for a deployment preset.\nValues are never returned because credentials are created only when a\ndeployment is planned and must remain write-only.", "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" ], "x-maturity": "experimental" } }, "/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\"`.\nIgnored when `start_time` and `end_time` are both set.", "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" ] } }, { "description": "Explicit window start (ISO 8601). Must be paired with `end_time`.", "example": "2026-08-13T00:00:00Z", "in": "query", "name": "start_time", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Explicit window end (ISO 8601). Must be paired with `start_time`.", "example": "2026-08-13T12:00:00Z", "in": "query", "name": "end_time", "required": false, "schema": { "type": [ "string", "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" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Provider is still used by domain delivery bindings" } }, "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" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Deactivation refused while domain delivery bindings use the provider" } }, "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" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Managed domain is still used by domain delivery bindings" } }, "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" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Turning off automatic management refused while domain delivery bindings use the zone, or a hostname-mode change refused while another generated-hostname operation runs on the zone (retryable)" } }, "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" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Invalid mode, or adopt/skip decisions that are duplicated, name a record type the sync never publishes, or were sent without sync_dns" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions or token lacks zone access" }, "404": { "description": "Domain not found" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Nothing was changed: a generated hostname's record conflicts and no decision adopts or skips it, an adopt or skip decision no longer matches the zone (preview again), or another generated-hostname operation is running on the zone (retry when it completes)" } }, "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-records": { "delete": { "operationId": "remove_managed_record", "parameters": [ { "description": "Domain (any FQDN under a managed zone)", "in": "query", "name": "domain", "required": true, "schema": { "type": "string" } }, { "description": "Record name relative to the zone (\"@\" for apex)", "in": "query", "name": "name", "required": true, "schema": { "type": "string" } }, { "description": "Record type", "in": "query", "name": "record_type", "required": true, "schema": { "$ref": "#/components/schemas/DnsRecordType" } } ], "responses": { "204": { "description": "Record removed (or already absent)" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Domain not managed by any DNS provider" }, "409": { "description": "Record is not managed by temps, is owned by another workflow, or is busy" } }, "security": [ { "bearer_auth": [] } ], "summary": "Delete a managed DNS record (only records owned by this install)", "tags": [ "DNS Records" ] }, "post": { "operationId": "set_managed_record", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetManagedRecordRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DnsRecord" } } }, "description": "Record set" }, "400": { "description": "Validation error (e.g. proxied depth limit)" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Domain not managed by any DNS provider" }, "409": { "description": "Record exists and is not managed by temps" } }, "security": [ { "bearer_auth": [] } ], "summary": "Create or update a managed DNS record (ownership-guarded)", "tags": [ "DNS Records" ] } }, "/dns-records/import": { "post": { "operationId": "import_managed_record", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportManagedRecordRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportManagedRecordResponse" } } }, "description": "Record imported" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Record or managed domain not found" }, "409": { "description": "Record is owned by another temps install" } }, "security": [ { "bearer_auth": [] } ], "summary": "Import an existing DNS record into temps management (explicit adoption)", "tags": [ "DNS Records" ] } }, "/dns-records/ownership": { "get": { "operationId": "get_record_ownership", "parameters": [ { "description": "Domain (any FQDN under a managed zone)", "in": "query", "name": "domain", "required": true, "schema": { "type": "string" } }, { "description": "Record name relative to the zone (\"@\" for apex)", "in": "query", "name": "name", "required": true, "schema": { "type": "string" } }, { "description": "Record type", "in": "query", "name": "record_type", "required": true, "schema": { "$ref": "#/components/schemas/DnsRecordType" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RecordOwnershipResponse" } } }, "description": "Ownership state" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Domain not managed by any DNS provider" } }, "security": [ { "bearer_auth": [] } ], "summary": "Get the ownership state of a DNS record", "tags": [ "DNS Records" ] } }, "/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" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" } }, "security": [ { "bearer_auth": [] } ], "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" ] } }, { "description": "Sort column (defaults to created_at)", "in": "query", "name": "sort_by", "required": false, "schema": { "description": "Allowlisted sort columns for the paginated domain collection.", "enum": [ "created_at", "domain", "status", "expiration" ], "type": "string" } }, { "description": "Sort direction (defaults to desc). Unknown expiration dates always sort last.", "in": "query", "name": "sort_order", "required": false, "schema": { "enum": [ "asc", "desc" ], "type": "string" } } ], "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" }, "400": { "description": "Bad request - account email or ACME order is invalid" }, "401": { "description": "Unauthorized" }, "403": { "description": "Domain or DNS provider permission denied" }, "404": { "description": "Domain or order not found" }, "409": { "description": "Certificate issued but DNS cleanup requires operator action" }, "500": { "description": "Internal server error" }, "502": { "description": "Certificate issued but DNS provider cleanup failed" }, "503": { "description": "Certificate issued but DNS provider service is unavailable" } }, "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" }, "409": { "description": "Ambiguous managed DNS zone" }, "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" ], "x-maturity": "experimental" } }, "/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" }, "400": { "description": "Bad request - account email or challenge is invalid" }, "401": { "description": "Unauthorized" }, "403": { "description": "Domain permission denied or a user account is required" }, "404": { "description": "Domain not found" }, "409": { "description": "DNS cleanup-aware order must use the finalize endpoint" }, "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}/renewal-attempts": { "get": { "description": "Returns rows from the append-only `renewal_attempts` audit log, newest\nfirst: every `request_challenge` (order creation) and `complete_challenge`\n(order finalization) attempt for this domain, successful or failed, with\nthe full error detail. Backs the domain detail page's renewal timeline —\n`domains.last_error` only ever holds the MOST RECENT failure, so this is\nthe only way to see the history behind it.", "operationId": "list_renewal_attempts", "parameters": [ { "description": "Domain name", "in": "path", "name": "domain", "required": true, "schema": { "type": "string" } }, { "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/ListRenewalAttemptsResponse" } } }, "description": "Renewal attempts retrieved successfully" }, "401": { "description": "Unauthorized" }, "404": { "description": "Domain not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "List certificate renewal attempts for a domain", "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/import": { "post": { "description": "Use this endpoint when the domain identity was created directly in the email\nprovider's console or API. Temps will fetch its current verification state\nrather than registering a new identity, preventing duplicate or conflicting\nprovider-side entries.", "operationId": "import_email_domain", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportEmailDomainRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailDomainWithDnsResponse" } } }, "description": "Domain imported successfully" }, "400": { "description": "Invalid request or provider lookup failed" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Provider not found" }, "409": { "description": "Domain already registered for this provider" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Import an already-provisioned email domain from the provider", "tags": [ "Email Domains" ] } }, "/email-domains/{id}": { "delete": { "description": "By default this only removes the Temps-side record; the domain identity\non the provider (Scaleway/SES) is left intact, since it may be shared\nwith other tools against that provider account. Pass\n`delete_from_provider=true` to also remove it on the provider's side. In\neither case, the local record is deleted regardless of whether that\nprovider-side deletion succeeds — an unreachable provider never blocks\nremoving the domain from Temps.", "operationId": "delete_email_domain", "parameters": [ { "description": "Domain ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Also remove the domain identity on the provider's side (Scaleway/SES),\nnot just the local Temps record. Defaults to `false`: the same domain\nmay be shared with other tools against that provider account, so\ndeleting it from Temps must not silently un-register it elsewhere\nunless explicitly requested. If the provider-side deletion fails\n(network error, revoked credentials), the local record is still\ndeleted -- an unreachable provider never blocks removing it from Temps.", "in": "query", "name": "delete_from_provider", "required": false, "schema": { "type": "boolean" } } ], "responses": { "204": { "description": "Domain deleted" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Domain not found" }, "500": { "description": "Internal server error (includes provider-side cleanup failure; the local record is still deleted)" } }, "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}/projects": { "get": { "operationId": "list_email_domain_projects", "parameters": [ { "description": "Email domain ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/AuthorizedEmailDomainProjectResponse" }, "type": "array" } } }, "description": "Projects authorized to use this sender domain" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Domain not found" }, "500": { "description": "Project visibility or database check failed" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Email Domains" ] } }, "/email-domains/{id}/projects/{project_id}": { "delete": { "operationId": "revoke_email_domain_project", "parameters": [ { "description": "Email domain ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Project whose authorization is revoked", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "204": { "description": "Project authorization revoked" }, "401": { "description": "Unauthorized" }, "403": { "description": "Only an instance or platform administrator may change global sender-domain grants" }, "404": { "description": "Domain not found" }, "500": { "description": "Project access, audit, or database check failed" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Email Domains" ] }, "post": { "operationId": "authorize_email_domain_project", "parameters": [ { "description": "Email domain ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Project allowed to send from this domain", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "204": { "description": "Project authorized" }, "401": { "description": "Unauthorized" }, "403": { "description": "Only an instance or platform administrator may change global sender-domain grants" }, "404": { "description": "Domain or project not found" }, "500": { "description": "Project access, audit, or database check failed" } }, "security": [ { "bearer_auth": [] } ], "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 or validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "422": { "description": "Provider credentials are invalid — the provider API definitively rejected them" }, "500": { "description": "Internal server error" }, "502": { "description": "Could not reach the provider API to verify credentials — the credentials may still be valid" } }, "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" }, "422": { "description": "New credentials are invalid — the provider API definitively rejected them" }, "500": { "description": "Internal server error" }, "502": { "description": "Could not reach the provider API to verify new credentials" } }, "security": [ { "bearer_auth": [] } ], "summary": "Update an email provider", "tags": [ "Email Providers" ] } }, "/email-providers/{id}/discoverable-domains": { "get": { "description": "Always returns `200`, even when the provider type has no domain-listing\nAPI (SMTP) or the live fetch failed — `supported: false` or a non-null\n`error` signal the caller to fall back to manual entry instead of\ntreating this as a hard failure. Only a genuine failure to resolve the\nprovider itself (not found, undecryptable credentials) returns an error\nstatus.", "operationId": "list_discoverable_domains", "parameters": [ { "description": "Provider ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListProviderDomainsResponse" } } }, "description": "Discoverable domains (see `supported`/`error` for fallback state)" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Provider not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "List domain identities already registered on a provider's side, for\npopulating an \"import existing domain\" picker instead of requiring the\noperator to type the domain name (and, for Scaleway, its internal UUID)\nby hand.", "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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", "parameters": [ { "description": "Required for deployment-token requests. Reusing a key with the same payload returns the original delivery; reusing it with a different payload returns 409.", "in": "header", "name": "Idempotency-Key", "required": false, "schema": { "type": [ "string", "null" ] } } ], "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" }, "409": { "description": "Idempotency key was already used with a different payload" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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": { "307": { "description": "Redirect to original URL" }, "404": { "description": "Link not found" } }, "summary": "Track email link click - redirects to original URL", "tags": [ "Email Tracking" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/error-groups": { "get": { "operationId": "list_global_error_groups", "parameters": [ { "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": "project_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "in": "query", "name": "status", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "search", "required": false, "schema": { "type": [ "string", "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" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalErrorGroupsResponse" } } }, "description": "Visible errors across projects" }, "400": { "description": "Invalid filters" }, "403": { "description": "Access denied" } }, "summary": "List issues across every project visible to the caller.", "tags": [ "error-tracking" ], "x-maturity": "beta" } }, "/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" } }, { "description": "Number of items per page (max 100)", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": "string" } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": "string" } } ], "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": { "description": "Create a managed external service. The `parameters` object is service-type-specific. Read `get_service_type_parameters` for the chosen `service_type` immediately before creating the service and provide every field that schema marks as required. Set `project_id` to create and link the service in one approval-gated operation.", "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" ], "x-maturity": "beta" } }, "/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" } }, { "description": "Number of items per page (max 100)", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": "string" } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": "string" } } ], "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 (mariadb, mongodb, postgres, redis, s3, kv, blob, rustfs, or legacy minio)", "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}/continuous-archive-source": { "post": { "description": "Deliberately, explicitly moves where a service's continuous, standing\narchiving process writes: Postgres/Timescale's WAL-G `archive_command`,\nor MariaDB's binlog shipper. Both need everything written under one S3\nprefix to stay restorable — data archived before this call lives under\nthe *previous* source and will no longer be verifiable or replayable\nonce archiving points at the new one.\n\nThis exists because a backup schedule that requests a different S3\nsource than the one archiving is currently pinned to is refused, not\nsilently honoured (see `ExternalServiceManager::repoint_continuous_archive_source`\nfor the incident this prevents). Call this endpoint to deliberately move\nthe pin instead — for example, to switch a service from an operator's\nown S3 source onto Temps Cloud's managed one.", "operationId": "repointContinuousArchiveSource", "parameters": [ { "description": "External service ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RepointContinuousArchiveSourceRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContinuousArchiveSourceResponse" } } }, "description": "Continuous archive source repointed" }, "400": { "description": "Service type does not support continuous archiving, or the requested S3 source does not exist" }, "404": { "description": "Service not found" }, "500": { "description": "Internal server error" } }, "summary": "Repoint a service's continuous archive source", "tags": [ "External Services" ] } }, "/external-services/{id}/environment": { "get": { "operationId": "reveal_service_environment_variables", "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": "Service environment variables in plaintext" }, "403": { "description": "Caller cannot access a project linked to this service" }, "404": { "description": "Service not found" }, "500": { "description": "Internal server error" } }, "summary": "Reveal a service's basic environment variables in plaintext, before it is\nlinked to any project. Used by the new-project wizard to fill a detected\nvariable (e.g. `DATABASE_URL`) from a service the user just picked or\ncreated — every successful reveal is recorded, matching the audited\nsingle-variable reveal used once a service is project-linked.", "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\"`.\nIgnored when `start_time` and `end_time` are both set.", "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" ] } }, { "description": "Explicit window start (ISO 8601). Must be paired with `end_time`.", "example": "2026-08-13T00:00:00Z", "in": "query", "name": "start_time", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Explicit window end (ISO 8601). Must be paired with `start_time`.", "example": "2026-08-13T12:00:00Z", "in": "query", "name": "end_time", "required": false, "schema": { "type": [ "string", "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" ], "x-maturity": "beta" }, "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" }, "409": { "description": "The service already has the maximum number of alert rules" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Create a monitoring alert rule for an external service.", "tags": [ "Metrics" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" } }, { "description": "Number of items per page (max 100)", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": "string" } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ProjectServiceInfo" }, "type": "array" } } }, "description": "List of linked projects" }, "401": { "description": "Authentication required" }, "403": { "description": "Insufficient permission to view this service" }, "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" }, "400": { "description": "Invalid database provisioning configuration" }, "401": { "description": "Authentication required" }, "403": { "description": "Insufficient permission to link this service" }, "404": { "description": "Service or project not found" }, "409": { "description": "Project already has a database of this type" }, "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" }, "401": { "description": "Authentication required" }, "403": { "description": "Insufficient permission to unlink this service" }, "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}/projects/{project_id}/environments/{environment_id}/runtime-credentials": { "post": { "description": "Provisions the per-tenant database if it does not exist yet, then returns\nthe connection variables in plaintext — the same values a deployment gets\ninjected at runtime.\n\n**This is a POST because it is not a read.** It creates a database as a\nside effect, and its response is a live credential: a GET would be\nprefetchable, cacheable, and liable to end up in a proxy access log with\nthe whole connection in the URL's neighbourhood. Nothing about it is safe\nor idempotent in the HTTP sense.\n\nIntended for callers that need to *connect* an application to a managed\nservice — the console's own deploy path does this in-process; external\nplugins reach it here. For inspecting configuration, use the masked bulk\nread or the single-variable reveal instead.", "operationId": "issue_runtime_credentials", "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 ID", "in": "path", "name": "environment_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RuntimeCredentialsResponse" } } }, "description": "Connection credentials issued" }, "403": { "description": "Plaintext secret access is not permitted" }, "404": { "description": "Service, project, or environment not found" }, "409": { "description": "Service is not linked to the project" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Issue live connection credentials for a service in an environment", "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" }, "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 or service not found" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Conflict: a destructive cross-service restore requires explicit confirmation (`cross-service-restore-not-confirmed`), another restore is already active on this service (`restore-already-active`, with `active_restore_run_id`), or the backup is being deleted" } }, "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" }, "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" } }, "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" }, "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 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" }, "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" } }, "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "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/status": { "get": { "operationId": "get_geo_database_status", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GeoDatabaseStatusResponse" } } }, "description": "Geolocation database status retrieved" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Authentication required" }, "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 freshness of the geolocation database", "tags": [ "geo" ] } }, "/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" ] }, "get": { "description": "Returns the connection's account, sync and health state. Credential values\nare never included; `has_authenticated_credentials` reports only whether\nthe connection can make authenticated provider requests.", "operationId": "get_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/ConnectionResponse" } } }, "description": "Connection details" }, "401": { "description": "Unauthorized" }, "404": { "description": "Connection not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Get a single 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" } }, { "description": "Cached default-branch preset slug; __undetected__ means not inspected", "in": "query", "name": "preset", "required": false, "schema": { "type": "string" } }, { "description": "Updated on or after this RFC3339 timestamp", "in": "query", "name": "updated_after", "required": false, "schema": { "type": "string" } } ], "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" }, "400": { "description": "Invalid token configuration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Git provider permission required" }, "404": { "description": "Connection not found" }, "429": { "description": "Git provider rate limit exceeded" }, "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" }, "403": { "description": "Git provider permission required" }, "404": { "description": "Connection not found" }, "429": { "description": "Git provider rate limit exceeded" }, "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" } }, { "description": "Cached default-branch preset slug; __undetected__ means not inspected", "in": "query", "name": "preset", "required": false, "schema": { "type": "string" } }, { "description": "Updated on or after this RFC3339 timestamp", "in": "query", "name": "updated_after", "required": false, "schema": { "type": "string" } } ], "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" } }, { "description": "HTTPS/443 origin of a self-hosted GitLab instance. Requires authentication and git_repositories:read.", "in": "query", "name": "base_url", "required": false, "schema": { "type": [ "string", "null" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublicRepositoryInfo" } } }, "description": "Repository information" }, "400": { "description": "Provider not supported" }, "401": { "description": "Authentication required for custom GitLab origins" }, "403": { "description": "Git provider permission required" }, "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": "HTTPS/443 origin of a self-hosted GitLab instance. Requires authentication and git_repositories:read.", "in": "query", "name": "base_url", "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/BranchListResponse" } } }, "description": "List of branches" }, "400": { "description": "Provider not supported" }, "401": { "description": "Authentication required for custom GitLab origins" }, "403": { "description": "Git provider permission required" }, "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}/compose-file": { "get": { "operationId": "get_public_compose_services", "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": "HTTPS/443 origin of a self-hosted GitLab instance. Requires authentication and git_repositories:read.", "in": "query", "name": "base_url", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Branch to read the compose file from (default: repository's default branch)", "in": "query", "name": "branch", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Compose file path to fetch and parse (from the `compose_files` list\n`/preset` already returned, or a custom path the user typed)", "in": "query", "name": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublicComposeServicesResponse" } } }, "description": "Compose services parsed successfully" }, "400": { "description": "Provider not supported, or the compose file could not be parsed" }, "401": { "description": "Authentication required for custom GitLab origins" }, "403": { "description": "Git provider permission required" }, "404": { "description": "Repository, branch, or compose file not found" }, "429": { "description": "API rate limit exceeded" }, "500": { "description": "Internal server error" } }, "summary": "Parse a compose file's services for a public repository (supports GitHub\nand GitLab). Unlike env-example detection, the caller already knows the\npath (from the `compose_files` list `/preset` already returned), so this\nfetches that one file directly rather than scanning the tree first.", "tags": [ "Public Repositories" ] }, "post": { "operationId": "get_public_compose_preview", "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": "HTTPS/443 origin of a self-hosted GitLab instance. Requires authentication and git_repositories:read.", "in": "query", "name": "base_url", "required": false, "schema": { "type": [ "string", "null" ] } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublicComposePreviewRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublicComposePreviewResponse" } } }, "description": "Effective Compose preview rendered" }, "400": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ComposePreviewProblemResponse" } } }, "description": "Compose file or override is invalid" }, "401": { "description": "Authentication required for custom GitLab origins" }, "403": { "description": "Git provider permission required" }, "404": { "description": "Repository, branch, or compose file not found" } }, "summary": "Render a redacted effective Compose preview for a public repository.", "tags": [ "Public Repositories" ] } }, "/git/public/{provider}/{owner}/{repo}/env-example": { "get": { "operationId": "detect_public_env_example", "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": "HTTPS/443 origin of a self-hosted GitLab instance. Requires authentication and git_repositories:read.", "in": "query", "name": "base_url", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Branch name to inspect (default: repository's default branch)", "in": "query", "name": "branch", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Project root directory to search (default: repository root)", "in": "query", "name": "root_directory", "required": false, "schema": { "type": [ "string", "null" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublicEnvExampleResponse" } } }, "description": "Detected env-example variables" }, "400": { "description": "Provider not supported" }, "401": { "description": "Authentication required for custom GitLab origins" }, "403": { "description": "Git provider permission required" }, "404": { "description": "Repository or branch not found" }, "429": { "description": "API rate limit exceeded" }, "500": { "description": "Internal server error" } }, "summary": "Detect and parse a `.env.example`-style file for a public repository\n(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": "HTTPS/443 origin of a self-hosted GitLab instance. Requires authentication and git_repositories:read.", "in": "query", "name": "base_url", "required": false, "schema": { "type": [ "string", "null" ] } }, { "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" }, "401": { "description": "Authentication required for custom GitLab origins" }, "403": { "description": "Git provider permission required" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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 or live sandboxes" }, "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" }, "400": { "description": "Invalid heartbeat payload" }, "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}/network/wireguard": { "put": { "description": "Called by the node's own agent. Stores its mesh public key and endpoint,\nassigns a mesh address on first call, makes that address the node's\noverlay underlay, and allocates the node's compute CIDR if the join could\nnot (a node that registered with a public address has no private underlay\nuntil now).", "operationId": "WireguardMeshRegister", "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/RegisterWireguardMeshRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegisterWireguardMeshResponse" } } }, "description": "Mesh address and port for this node" }, "400": { "description": "Invalid public key or endpoint" }, "401": { "description": "Missing or invalid bearer token" }, "404": { "description": "Node not found" }, "409": { "description": "Mesh disabled, key already in use, or pool exhausted" }, "500": { "description": "Internal server error" } }, "summary": "`PUT /internal/nodes/{node_id}/network/wireguard`", "tags": [ "Nodes" ] } }, "/internal/nodes/{node_id}/network/wireguard/handshakes": { "put": { "description": "Called by the node's own agent after each mesh sync. The control plane\nroutes pairs whose direct link never handshakes through the hub (ADR 048\nD4).", "operationId": "WireguardMeshHandshakesReport", "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/ReportWireguardHandshakesRequest" } } }, "required": true }, "responses": { "204": { "description": "Report recorded" }, "400": { "description": "Too many peers" }, "401": { "description": "Missing or invalid bearer token" }, "500": { "description": "Internal server error" } }, "summary": "`PUT /internal/nodes/{node_id}/network/wireguard/handshakes`", "tags": [ "Nodes" ] } }, "/internal/nodes/{node_id}/public-ingress": { "patch": { "operationId": "admin_set_node_public_ingress", "parameters": [ { "in": "path", "name": "node_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetNodePublicIngressRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetNodePublicIngressResponse" } } } }, "400": { "description": "Node is not a worker" }, "404": { "description": "Node not found" } }, "security": [ { "bearer_auth": [] } ], "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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": "Target line timestamp (RFC 3339)", "in": "query", "name": "timestamp", "required": true, "schema": { "type": "string" } }, { "description": "Target line container ID", "in": "query", "name": "container_id", "required": true, "schema": { "type": "string" } }, { "description": "Target line_id, as a decimal string", "in": "query", "name": "line_id", "required": true, "schema": { "type": "string" } }, { "description": "Context lines before and after (default: 25, max 50)", "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": "Line 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/global/aggregate": { "get": { "operationId": "global_log_aggregate", "parameters": [ { "description": "Window start (RFC 3339)", "in": "query", "name": "start_time", "required": true, "schema": { "type": "string" } }, { "description": "Window end (RFC 3339)", "in": "query", "name": "end_time", "required": true, "schema": { "type": "string" } }, { "description": "Source kind (default: all)", "in": "query", "name": "source", "required": false, "schema": { "$ref": "#/components/schemas/LogSourceKind" } }, { "description": "Project selectors (repeatable)", "in": "query", "name": "projects", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "External service selectors (repeatable)", "in": "query", "name": "external_services", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Scope selectors (repeatable)", "in": "query", "name": "scopes", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Levels (repeatable)", "in": "query", "name": "levels", "required": false, "schema": { "items": { "$ref": "#/components/schemas/LogLevel" }, "type": "array" } }, { "description": "Environments (repeatable)", "in": "query", "name": "envs", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Services (repeatable)", "in": "query", "name": "services", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Container ids (repeatable)", "in": "query", "name": "container_ids", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Node ids (repeatable)", "in": "query", "name": "node_ids", "required": false, "schema": { "items": { "format": "int32", "type": "integer" }, "type": "array" } }, { "description": "Deployment id", "in": "query", "name": "deploy_id", "required": false, "schema": { "format": "int32", "type": "integer" } }, { "description": "Comma-separated label names and/or attr:", "in": "query", "name": "group_by", "required": true, "schema": { "type": "string" } }, { "description": "count | count_distinct: | avg: | p50: | p95: | p99: | max: | sum:", "in": "query", "name": "metric", "required": true, "schema": { "type": "string" } }, { "description": "Max rows returned (default 50, cap 1000)", "in": "query", "name": "limit", "required": false, "schema": { "format": "int32", "minimum": 0, "type": "integer" } }, { "description": "Repeatable attribute predicate: or ?", "in": "query", "name": "attr", "required": true, "schema": { "items": { "type": "string" }, "type": "array" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AggregateResponse" } } } }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "503": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Logs" ] } }, "/logs/global/attributes": { "get": { "operationId": "global_log_attribute_keys", "parameters": [ { "description": "Window start (RFC 3339)", "in": "query", "name": "start_time", "required": true, "schema": { "type": "string" } }, { "description": "Window end (RFC 3339)", "in": "query", "name": "end_time", "required": true, "schema": { "type": "string" } }, { "description": "Source kind (default: all)", "in": "query", "name": "source", "required": false, "schema": { "$ref": "#/components/schemas/LogSourceKind" } }, { "description": "Project selectors (repeatable)", "in": "query", "name": "projects", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "External service selectors (repeatable)", "in": "query", "name": "external_services", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Scope selectors (repeatable)", "in": "query", "name": "scopes", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Levels (repeatable)", "in": "query", "name": "levels", "required": false, "schema": { "items": { "$ref": "#/components/schemas/LogLevel" }, "type": "array" } }, { "description": "Environments (repeatable)", "in": "query", "name": "envs", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Services (repeatable)", "in": "query", "name": "services", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Container ids (repeatable)", "in": "query", "name": "container_ids", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Node ids (repeatable)", "in": "query", "name": "node_ids", "required": false, "schema": { "items": { "format": "int32", "type": "integer" }, "type": "array" } }, { "description": "Deployment id", "in": "query", "name": "deploy_id", "required": false, "schema": { "format": "int32", "type": "integer" } }, { "description": "Max keys returned (default/cap 1000)", "in": "query", "name": "limit", "required": false, "schema": { "format": "int32", "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AttributeKeysResponse" } } } }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "503": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Logs" ] } }, "/logs/global/capabilities": { "get": { "operationId": "global_log_capabilities", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalLogCapabilities" } } } }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Logs" ] } }, "/logs/global/facets": { "post": { "operationId": "facet_global_logs", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalLogFacetsRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalLogFacetsResponse" } } } }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "408": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Logs" ] } }, "/logs/global/facets/attrs": { "get": { "operationId": "global_log_facets_attrs", "parameters": [ { "description": "Window start (RFC 3339)", "in": "query", "name": "start_time", "required": true, "schema": { "type": "string" } }, { "description": "Window end (RFC 3339)", "in": "query", "name": "end_time", "required": true, "schema": { "type": "string" } }, { "description": "Source kind (default: all)", "in": "query", "name": "source", "required": false, "schema": { "$ref": "#/components/schemas/LogSourceKind" } }, { "description": "Project selectors (repeatable)", "in": "query", "name": "projects", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "External service selectors (repeatable)", "in": "query", "name": "external_services", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Scope selectors (repeatable)", "in": "query", "name": "scopes", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Levels (repeatable)", "in": "query", "name": "levels", "required": false, "schema": { "items": { "$ref": "#/components/schemas/LogLevel" }, "type": "array" } }, { "description": "Environments (repeatable)", "in": "query", "name": "envs", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Services (repeatable)", "in": "query", "name": "services", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Container ids (repeatable)", "in": "query", "name": "container_ids", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Node ids (repeatable)", "in": "query", "name": "node_ids", "required": false, "schema": { "items": { "format": "int32", "type": "integer" }, "type": "array" } }, { "description": "Deployment id", "in": "query", "name": "deploy_id", "required": false, "schema": { "format": "int32", "type": "integer" } }, { "description": "Comma-separated label names or attr:", "in": "query", "name": "keys", "required": true, "schema": { "type": "string" } }, { "description": "Repeatable attribute predicate: or ?", "in": "query", "name": "attr", "required": true, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Max values per key (default/cap 1000)", "in": "query", "name": "limit", "required": false, "schema": { "format": "int32", "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FacetsAttrsResponse" } } } }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "503": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Logs" ] } }, "/logs/global/histogram": { "get": { "operationId": "global_log_histogram", "parameters": [ { "description": "Window start (RFC 3339)", "in": "query", "name": "start_time", "required": true, "schema": { "type": "string" } }, { "description": "Window end (RFC 3339)", "in": "query", "name": "end_time", "required": true, "schema": { "type": "string" } }, { "description": "Source kind (default: all)", "in": "query", "name": "source", "required": false, "schema": { "$ref": "#/components/schemas/LogSourceKind" } }, { "description": "Project selectors (repeatable)", "in": "query", "name": "projects", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "External service selectors (repeatable)", "in": "query", "name": "external_services", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Scope selectors (repeatable)", "in": "query", "name": "scopes", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Levels (repeatable)", "in": "query", "name": "levels", "required": false, "schema": { "items": { "$ref": "#/components/schemas/LogLevel" }, "type": "array" } }, { "description": "Environments (repeatable)", "in": "query", "name": "envs", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Services (repeatable)", "in": "query", "name": "services", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Container ids (repeatable)", "in": "query", "name": "container_ids", "required": false, "schema": { "items": { "type": "string" }, "type": "array" } }, { "description": "Node ids (repeatable)", "in": "query", "name": "node_ids", "required": false, "schema": { "items": { "format": "int32", "type": "integer" }, "type": "array" } }, { "description": "Deployment id", "in": "query", "name": "deploy_id", "required": false, "schema": { "format": "int32", "type": "integer" } }, { "description": "Bucket width in seconds (default 60)", "in": "query", "name": "bucket_secs", "required": false, "schema": { "format": "int32", "minimum": 0, "type": "integer" } }, { "description": "One label name or attr: to split series by", "in": "query", "name": "group_by", "required": false, "schema": { "type": "string" } }, { "description": "Max series before folding the rest into \"other\" (default 8)", "in": "query", "name": "max_groups", "required": false, "schema": { "format": "int32", "minimum": 0, "type": "integer" } }, { "description": "Repeatable attribute predicate: or ?", "in": "query", "name": "attr", "required": true, "schema": { "items": { "type": "string" }, "type": "array" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HistogramResponse" } } } }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "503": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Logs" ] } }, "/logs/global/search": { "post": { "operationId": "search_global_logs", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalLogSearchRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalLogSearchResponse" } } } }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "408": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "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" }, "403": { "description": "Insufficient permissions" }, "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" ] }, "patch": { "operationId": "update_monitor", "parameters": [ { "description": "Monitor ID", "in": "path", "name": "monitor_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateMonitorRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MonitorResponse" } } }, "description": "Monitor updated successfully" }, "400": { "description": "Invalid request" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Monitor not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Update a monitor's check path", "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": false, "schema": { "type": "string" } }, { "description": "End time (ISO 8601) - defaults to now", "in": "query", "name": "end_time", "required": false, "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/capability": { "get": { "description": "A control plane with no local workloads and no joined worker node accepts\ndeploys it can never run. Rather than letting every surface learn that by\nfailing, this endpoint states it up front so the console can render an\nonboarding state with a link to join a node — and so a client can tell\n\"not set up\" apart from \"not built\", which a 404 or a 500 cannot.", "operationId": "NodeCapabilityGet", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeCapabilityResponse" } } }, "description": "Scheduling capability of this install" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Report whether this install can schedule workloads.", "tags": [ "Nodes" ], "x-maturity": "beta" } }, "/nodes/pairings": { "get": { "operationId": "NodePairingList", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodePairingListResponse" } } }, "description": "Node pairings" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Recent node pairings, newest first.", "tags": [ "Nodes" ], "x-maturity": "beta" }, "post": { "operationId": "NodePairingCreate", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateNodePairingRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateNodePairingResponse" } } }, "description": "Pairing created" }, "400": { "description": "Invalid address or name" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "409": { "description": "The mesh is off or its control-plane end is not up" }, "428": { "description": "Re-authentication required" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Pair a node the control plane can reach: returns the command to run on\nit. The control plane then dials the node until it answers or the pairing\nexpires (30 minutes).", "tags": [ "Nodes" ], "x-maturity": "beta" } }, "/nodes/pairings/{pairing_id}": { "delete": { "operationId": "NodePairingCancel", "parameters": [ { "description": "Pairing ID", "in": "path", "name": "pairing_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "204": { "description": "Pairing cancelled" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "No such pairing" }, "409": { "description": "The pairing already finished" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Cancel a pending pairing: the control plane stops dialing the node, the\ncode stops working and its mesh address is released.", "tags": [ "Nodes" ], "x-maturity": "beta" } }, "/nodes/ssh/enrollments": { "get": { "operationId": "NodeSshEnrollmentList", "parameters": [ { "description": "Page, from 1 (default 1).", "in": "query", "name": "page", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "description": "Enrollments per page (default 20, at most 100).", "in": "query", "name": "per_page", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeSshEnrollmentListResponse" } } }, "description": "SSH enrollments" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Servers added over SSH, newest first, a page at a time. Items leave out\nthe log; `GET /nodes/ssh/enrollments/{enrollment_id}` has it.", "tags": [ "Nodes" ], "x-maturity": "beta" }, "post": { "operationId": "NodeSshEnrollmentCreate", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeSshEnrollmentCreateRequest" } } }, "required": true }, "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeSshEnrollmentResponse" } } }, "description": "Enrollment started" }, "400": { "description": "Invalid host, user, fingerprint or name" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "409": { "description": "The mesh is off or not ready, or too many enrollments are running" }, "428": { "description": "Re-authentication required" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Add a server over SSH: log in with the given credentials, install `temps`\nif needed, pair the server and start its agent. Runs in the background;\nfollow it with `GET /nodes/ssh/enrollments/{enrollment_id}`.", "tags": [ "Nodes" ], "x-maturity": "beta" } }, "/nodes/ssh/enrollments/{enrollment_id}": { "get": { "operationId": "NodeSshEnrollmentGet", "parameters": [ { "description": "Enrollment ID", "in": "path", "name": "enrollment_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeSshEnrollmentResponse" } } }, "description": "The enrollment" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "No such enrollment" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "One server being added over SSH, with its progress and log.", "tags": [ "Nodes" ], "x-maturity": "beta" } }, "/nodes/ssh/host-key": { "post": { "operationId": "NodeSshHostKey", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeSshHostKeyRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeSshHostKeyResponse" } } }, "description": "The server's host key" }, "400": { "description": "Invalid or unusable host" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "428": { "description": "Re-authentication required" }, "502": { "description": "The server could not be reached over SSH" } }, "security": [ { "bearer_auth": [] } ], "summary": "Read a server's SSH host key, without logging in, so the operator can\nconfirm it before adding the server.", "tags": [ "Nodes" ], "x-maturity": "beta" } }, "/nodes/wireguard": { "get": { "operationId": "WireguardMeshStatusGet", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WireguardMeshStatusResponse" } } }, "description": "WireGuard mesh state" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Mesh state, per-node connection and join onboarding for the Worker Nodes\npage.", "tags": [ "Nodes" ], "x-maturity": "beta" }, "post": { "operationId": "WireguardMeshEnable", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EnableWireguardMeshRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WireguardMeshStatusResponse" } } }, "description": "Mesh enabled; current state" }, "400": { "description": "Invalid pool or port" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "409": { "description": "This server cannot bring up the mesh, or the pool/port is in use" }, "428": { "description": "Re-authentication required" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Turn on the cluster's WireGuard mesh (idempotent). The running control\nplane brings its end up within a minute and nodes follow; it cannot be\nturned off again from the API.", "tags": [ "Nodes" ], "x-maturity": "beta" } }, "/nodes/wireguard/hub": { "put": { "operationId": "WireguardMeshHubSet", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetWireguardMeshHubRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WireguardMeshStatusResponse" } } }, "description": "Hub set; current state" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "No such node" }, "409": { "description": "The mesh is off, or the member is not on it" }, "428": { "description": "Re-authentication required" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Make a member the mesh hub, or remove the hub (ADR 048 D4). The hub\nrelays traffic between members that cannot reach each other, so it sees\nthat traffic: pick one of your own machines.", "tags": [ "Nodes" ], "x-maturity": "beta" } }, "/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\"`.\nIgnored when `start_time` and `end_time` are both set.", "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" ] } }, { "description": "Explicit window start (ISO 8601). Must be paired with `end_time`.", "example": "2026-08-13T00:00:00Z", "in": "query", "name": "start_time", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Explicit window end (ISO 8601). Must be paired with `start_time`.", "example": "2026-08-13T12:00:00Z", "in": "query", "name": "end_time", "required": false, "schema": { "type": [ "string", "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" ] } }, "/nodes/{id}/metrics/alert-rules": { "get": { "description": "Node `0` is the synthetic control-plane node, which owns the seeded\n`proxy.*` (error rate, p99 latency) and `node.*` (file-descriptor /\nsocket exhaustion) defaults. Without this endpoint those rules exist only\nin the database and the operator has no way to see that they are watching,\nlet alone retune or silence them.", "operationId": "NodeMetricsGetAlertRules", "parameters": [ { "description": "Node ID (0 = control plane)", "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 node alert rules" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "List the monitoring alert rules scoped to a node.", "tags": [ "Metrics" ], "x-maturity": "beta" } }, "/nodes/{id}/metrics/alert-rules/{rule_id}": { "patch": { "description": "Deliberately update-only: there is no delete. The control-plane defaults\nare re-seeded on every startup (`ON CONFLICT DO NOTHING`), so a deleted\nrule would silently reappear on the next restart, whereas `enabled: false`\nsurvives re-seeding — disabling is the operation that actually means\n\"stop alerting on this\".", "operationId": "NodeMetricsUpdateAlertRule", "parameters": [ { "description": "Node ID (0 = control plane)", "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 a node-scoped monitoring alert rule.", "tags": [ "Metrics" ], "x-maturity": "beta" } }, "/nodes/{id}/metrics/latest": { "get": { "description": "Node `0` is the synthetic control-plane node. This is what the server\nmonitoring page reads for its \"Used: X / Limit: Y\" headlines\n(`node.memory_used_bytes`, `node.disk_total_bytes`, …) and for the\ncumulative `*_bytes_total` I/O counters, without having to fetch a full\nrange for each series.", "operationId": "NodeMetricsGetLatest", "parameters": [ { "description": "Node ID (0 = control plane)", "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 of every metric on a node.", "tags": [ "Metrics" ], "x-maturity": "beta" } }, "/nodes/{node_id}/docker-disk-usage": { "get": { "description": "On-demand rather than sampled: walking every layer, rootfs and volume can\ntake seconds, so the server monitoring page fetches it when opened or when\nthe operator presses refresh. Node `0` only for now — a worker's daemon is\nonly reachable through its agent, which does not relay this yet, and the\nerror says exactly that instead of 404ing.", "operationId": "NodeDockerDiskUsageGet", "parameters": [ { "description": "Node ID (0 = control plane)", "in": "path", "name": "node_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DockerDiskUsage" } } }, "description": "Docker disk usage by category" }, "400": { "description": "Node is not the control plane" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" }, "502": { "description": "Docker daemon answered with an unexpected response" }, "503": { "description": "Docker daemon unreachable" }, "504": { "description": "Docker daemon timed out" } }, "security": [ { "bearer_auth": [] } ], "summary": "Docker disk usage (`docker system df`) for the control-plane host.", "tags": [ "Nodes" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" } }, { "description": "Number of items per page (max 100)", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": "string" } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": "string" } } ], "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" }, "400": { "description": "Invalid minimum severity or provider configuration" }, "404": { "description": "Provider not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Update a Cloudflare Email Sending notification provider", "tags": [ "Notification Providers" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" }, "400": { "description": "Invalid minimum severity or provider configuration" }, "404": { "description": "Provider not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Update an Email notification provider", "tags": [ "Notification Providers" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" }, "400": { "description": "Invalid minimum severity or provider configuration" }, "404": { "description": "Provider not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Update a Slack notification provider", "tags": [ "Notification Providers" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" }, "400": { "description": "Invalid minimum severity or provider configuration" }, "404": { "description": "Provider not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Update a Webhook notification provider", "tags": [ "Notification Providers" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" }, "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 minimum severity or masked provider configuration" }, "404": { "description": "Provider not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Update a notification provider", "tags": [ "Notification Providers" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/notification-routes": { "get": { "operationId": "list_notification_routes", "parameters": [ { "description": "Page number (1-indexed)", "example": 1, "in": "query", "name": "page", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "description": "Number of items per page (max 100)", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": "string" } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationRoutePage" } } }, "description": "Notification routes" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Notification Routes" ], "x-maturity": "beta" }, "post": { "operationId": "create_notification_route", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateNotificationRouteRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationRoute" } } }, "description": "Route created" }, "400": { "description": "Invalid route" }, "409": { "description": "Route name already exists" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Notification Routes" ], "x-maturity": "beta" } }, "/notification-routes/coverage": { "get": { "operationId": "get_notification_delivery_coverage", "parameters": [ { "description": "Severity of the notification to check: debug, info, warning, error,\ncritical or emergency.", "in": "query", "name": "severity", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationDeliveryCoverageResponse" } } }, "description": "Delivery coverage for the severity" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Invalid severity" }, "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 whether a notification of the given severity would be delivered", "tags": [ "Notification Routes" ], "x-maturity": "beta" } }, "/notification-routes/{id}": { "delete": { "operationId": "delete_notification_route", "parameters": [ { "description": "Route ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "204": { "description": "Route deleted" }, "404": { "description": "Route not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Notification Routes" ], "x-maturity": "beta" }, "get": { "operationId": "get_notification_route", "parameters": [ { "description": "Route ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationRoute" } } }, "description": "Notification route" }, "404": { "description": "Route not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Notification Routes" ], "x-maturity": "beta" }, "put": { "operationId": "update_notification_route", "parameters": [ { "description": "Route ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateNotificationRouteRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationRoute" } } }, "description": "Route updated" }, "400": { "description": "Invalid route" }, "404": { "description": "Route not found" }, "409": { "description": "Route name already exists" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Notification Routes" ], "x-maturity": "beta" } }, "/notification-routes/{id}/test": { "post": { "operationId": "test_notification_route", "parameters": [ { "description": "Route ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NotificationRouteTestResult" } } }, "description": "Per-provider test results" }, "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": "Route not found" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Send a test notification through a route to each of its providers", "tags": [ "Notification Routes" ], "x-maturity": "beta" } }, "/operations": { "get": { "description": "Deployments, rollbacks, promotions, restores, backups and autofix runs the\ncaller can see, newest first (`created_at` DESC, fixed). Finished\noperations older than 7 days are omitted; operations still in flight are\nalways included. Redeploys are reported as `deployment` — no column\ndistinguishes them.", "operationId": "list_operations", "parameters": [ { "description": "Page number, 1-based (default 1).", "example": 1, "in": "query", "name": "page", "required": false, "schema": { "format": "int64", "minimum": 1, "type": "integer" } }, { "description": "Items per page (default 20, max 100).", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "maximum": 100, "minimum": 1, "type": "integer" } }, { "description": "`running` (queued, running, waiting), `finished` (succeeded, failed,\ncancelled) or `all` (default).", "in": "query", "name": "status", "required": false, "schema": { "$ref": "#/components/schemas/OperationStatusFilter" } }, { "description": "Only operations of this kind.", "in": "query", "name": "kind", "required": false, "schema": { "$ref": "#/components/schemas/OperationKind" } }, { "description": "Only operations belonging to this project.", "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OperationsListResponse" } } }, "description": "A page of operations" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Invalid query" }, "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 recent and in-flight operations", "tags": [ "Operations" ] } }, "/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" } }, { "description": "Number of items per page (max 100)", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": "string" } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": "string" } } ], "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" ], "x-maturity": "beta" }, "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" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Project not found" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Project already holds the maximum number of metric alert rules" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/otel/cloud-telemetry/backfill/{project_id}": { "get": { "operationId": "get_cloud_backfill_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/CloudBackfillStatusResponse" } } }, "description": "Backfill 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": "Status of the most recent Temps Cloud telemetry backfill for a project.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/otel/cloud-telemetry/bulk-jobs": { "post": { "operationId": "create_bulk_activation_job", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateBulkActivationJobRequest" } } }, "required": true }, "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkActivationJobResponse" } } }, "description": "The activation was queued" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "The plan token is invalid, altered or expired" }, "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": "An activation is already running; the response carries its batch_id" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Queue the activation that was quoted.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/otel/cloud-telemetry/bulk-jobs/current": { "get": { "operationId": "get_current_bulk_activation_job", "responses": { "200": { "content": { "application/json": { "schema": { "oneOf": [ { "$ref": "#/components/schemas/BulkActivationJobResponse" }, { "type": "null" } ] } } }, "description": "The active activation job, or null when none is running" }, "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": "The activation currently pending or running, or `null`.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/otel/cloud-telemetry/bulk-jobs/estimate": { "post": { "operationId": "estimate_bulk_activation", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EstimateBulkActivationRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkActivationEstimateResponse" } } }, "description": "Per-project and total estimate, plus a plan token" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Neither or both scopes given, or an invalid window" }, "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": "Temps Cloud is not ready for telemetry" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Quote a bulk Cloud-telemetry activation. Sends nothing.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/otel/cloud-telemetry/bulk-jobs/{batch_id}": { "get": { "operationId": "get_bulk_activation_job", "parameters": [ { "description": "Activation job id (UUID)", "in": "path", "name": "batch_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkActivationJobResponse" } } }, "description": "The activation job" }, "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 such activation job" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "One activation job, with per-project rows and an ETA.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/otel/cloud-telemetry/bulk-jobs/{batch_id}/cancel": { "post": { "operationId": "cancel_bulk_activation_job", "parameters": [ { "description": "Activation job id (UUID)", "in": "path", "name": "batch_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkActivationJobResponse" } } }, "description": "The cancellation was recorded, or the job had already stopped" }, "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 such activation job" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Ask an activation to stop at the next chunk boundary.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/otel/cloud-telemetry/projects/{project_id}": { "get": { "operationId": "get_project_cloud_telemetry", "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/ProjectCloudTelemetryResponse" } } }, "description": "Project Cloud telemetry settings" }, "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": "Project not found" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "A project's Cloud telemetry write mode and fidelity.", "tags": [ "OTel" ], "x-maturity": "beta" }, "patch": { "operationId": "update_project_cloud_telemetry", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateProjectCloudTelemetryRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectCloudTelemetryResponse" } } }, "description": "Updated settings" }, "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": "Project not found" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "A prerequisite is missing" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Change a project's Cloud telemetry write mode and/or fidelity.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/otel/cloud-telemetry/status": { "get": { "operationId": "get_cloud_telemetry_status", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloudTelemetryWriteStatusResponse" } } }, "description": "Instance Cloud telemetry write 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": "Instance-wide Cloud telemetry write status.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/otel/facets": { "get": { "description": "Returns all facets registered on this platform (newest first). Since the\n`spans` ClickHouse table is platform-global, facets are also platform-global.", "operationId": "list_facets", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FacetsResponse" } } }, "description": "Registered facets" }, "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 registered OTel span attribute facets.", "tags": [ "OTel Facets" ], "x-maturity": "beta" }, "post": { "description": "Assigns the key to the lowest available slot column (1..=20) and inserts\nthe mapping into Postgres with `status: pending`. Returns immediately —\nthe historical backfill (populating the slot column for spans already\ningested before this call) runs entirely in the background, advanced by a\nperiodic poller; poll `GET /otel/facets` and check the returned `status`\n(`pending` -> `running` -> `completed`/`failed`) to track progress. New\nspans start getting the attribute written into the slot column right\naway, independent of backfill progress.", "operationId": "create_facet", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateFacetRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FacetInfo" } } }, "description": "Facet registered" }, "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" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Already registered or capacity exceeded" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Register an OTel attribute key as a facet.", "tags": [ "OTel Facets" ], "x-maturity": "beta" } }, "/otel/facets/{key}": { "delete": { "description": "Marks the facet `deleting` and stops new spans from populating its slot\nimmediately, but the Postgres row (and its slot reservation) isn't\nremoved until the background poller confirms the slot column has been\ncleared for all existing spans — otherwise a future facet reusing the\nsame slot could see stale data. `GET /otel/facets` will keep returning\nthis facet with `status: deleting` until that finishes.", "operationId": "delete_facet", "parameters": [ { "description": "The OTel attribute key (URL-encoded)", "in": "path", "name": "key", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Facet 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": "Facet not found" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Remove a registered OTel span attribute facet.", "tags": [ "OTel Facets" ], "x-maturity": "beta" } }, "/otel/facets/{key}/retry": { "post": { "description": "Only valid when the facet's `status` is `failed`. Resets its progress and\nlets the background poller re-attempt the backfill from the beginning on\nits next tick.", "operationId": "retry_facet_backfill", "parameters": [ { "description": "The OTel attribute key (URL-encoded)", "in": "path", "name": "key", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FacetInfo" } } }, "description": "Backfill retry scheduled" }, "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": "Facet not found" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Facet is not in a failed state" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Retry a failed OTel span attribute facet backfill.", "tags": [ "OTel Facets" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "experimental" } }, "/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" } }, { "description": "Window start (RFC 3339); pair with end_time, max 31 days", "in": "query", "name": "start_time", "required": false, "schema": { "type": "string" } }, { "description": "Window end (RFC 3339); pair with start_time, max 31 days", "in": "query", "name": "end_time", "required": false, "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" ], "x-maturity": "experimental" } }, "/otel/global/spans": { "get": { "operationId": "query_global_traces", "parameters": [ { "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "in": "query", "name": "trace_id", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "service_name", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "status", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "min_duration_ms", "required": false, "schema": { "format": "double", "type": [ "number", "null" ] } }, { "in": "query", "name": "start_time", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "end_time", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "environment_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "in": "query", "name": "deployment_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "description": "Filter by span attributes as comma-separated key=value pairs.\ne.g. \"gen_ai.system=openai,gen_ai.request.model=gpt-4\"", "in": "query", "name": "attributes", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Filter by span name pattern (ILIKE).", "in": "query", "name": "name_pattern", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Sort field for the trace-summaries list: \"start_time\" (default) or\n\"duration\". Anything else falls back to start_time.", "in": "query", "name": "sort_by", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Sort direction: \"asc\" or \"desc\" (default).", "in": "query", "name": "sort_order", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "limit", "required": false, "schema": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] } }, { "in": "query", "name": "offset", "required": false, "schema": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalTracesResponse" } } } }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Traces" ], "x-maturity": "beta" } }, "/otel/global/trace-summaries": { "get": { "operationId": "query_global_trace_summaries", "parameters": [ { "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "in": "query", "name": "trace_id", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "service_name", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "status", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "min_duration_ms", "required": false, "schema": { "format": "double", "type": [ "number", "null" ] } }, { "in": "query", "name": "start_time", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "end_time", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "environment_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "in": "query", "name": "deployment_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "description": "Filter by span attributes as comma-separated key=value pairs.\ne.g. \"gen_ai.system=openai,gen_ai.request.model=gpt-4\"", "in": "query", "name": "attributes", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Filter by span name pattern (ILIKE).", "in": "query", "name": "name_pattern", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Sort field for the trace-summaries list: \"start_time\" (default) or\n\"duration\". Anything else falls back to start_time.", "in": "query", "name": "sort_by", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Sort direction: \"asc\" or \"desc\" (default).", "in": "query", "name": "sort_order", "required": false, "schema": { "type": [ "string", "null" ] } }, { "in": "query", "name": "limit", "required": false, "schema": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] } }, { "in": "query", "name": "offset", "required": false, "schema": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalTraceSummariesResponse" } } } }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Traces" ], "x-maturity": "beta" } }, "/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" } }, { "description": "Window start (RFC 3339); pair with end_time, max 31 days", "in": "query", "name": "start_time", "required": false, "schema": { "type": "string" } }, { "description": "Window end (RFC 3339); pair with start_time, max 31 days", "in": "query", "name": "end_time", "required": false, "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" ], "x-maturity": "beta" } }, "/otel/has-traces/{project_id}": { "get": { "description": "A pure existence check for onboarding/setup UI (e.g. \"has this project\nset up OpenTelemetry yet?\"). Deliberately not `/otel/trace-summaries`\nwith `limit=1`: that endpoint aggregates by trace (`GROUP BY trace_id`,\n`argMax`) and, without a time bound, that aggregation runs over every\nspan the project has ever ingested. This endpoint answers the same\nyes/no question in O(1) — see `OtelStorage::has_traces`.", "operationId": "has_traces", "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/HasTracesResponse" } } }, "description": "Trace existence check" }, "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": "Whether a project has ever received at least one trace span.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/otel/ingest-errors": { "get": { "description": "The companion to `/otel/pipeline-stats`: that endpoint reports *how many*\nrecords were dropped, this one reports *why*, so an operator can tell a\nClickHouse outage from a schema mismatch without reading server logs.\n\nRead-only and system-scoped (no project parameter), matching\n`get_pipeline_stats` — the counters it explains are process-wide.", "operationId": "get_ingest_errors", "parameters": [ { "description": "Max groups to return (default 20, max 100)", "in": "query", "name": "limit", "required": false, "schema": { "format": "int32", "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IngestErrorsResponse" } } }, "description": "Recent ingest failure groups" }, "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 recent OTel ingest failures, grouped by signal and error class.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/otel/pipeline-history": { "get": { "description": "`/otel/pipeline-stats` gives lifetime totals and `/otel/ingest-errors`\ngives failure reasons; this gives the shape over time — whether drops are a\npast incident that already recovered or an ongoing bleed, which a\ncumulative counter can never show.\n\nReads the delta series the background sampler writes to the shared metrics\nstore (`SourceKind::Node`, node 0). Values are **mean deltas per sample\ninterval**, not bucket totals — `sample_interval_seconds` in the response\ncarries the unit so the client can label them.\n\nSystem-scoped like the other two pipeline endpoints: these counters are\nprocess-wide, so there is no project parameter to scope by.", "operationId": "get_pipeline_history", "parameters": [ { "description": "Preset window: 1h | 6h | 24h | 7d (default 24h). Ignored when start_time and end_time are both set.", "in": "query", "name": "range", "required": false, "schema": { "type": "string" } }, { "description": "Explicit window start (RFC 3339); must be paired with end_time", "in": "query", "name": "start_time", "required": false, "schema": { "type": "string" } }, { "description": "Explicit window end (RFC 3339); must be paired with start_time", "in": "query", "name": "end_time", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PipelineHistoryResponse" } } }, "description": "Pipeline counter history" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Invalid time range" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "503": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Metrics store not available" } }, "security": [ { "bearer_auth": [] } ], "summary": "Chart the OTel pipeline counters over time.", "tags": [ "OTel" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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 attributes as comma-separated key=value pairs, e.g. \"gen_ai.system=openai,gen_ai.request.model=gpt-4\"", "in": "query", "name": "attributes", "required": false, "schema": { "type": "string" } }, { "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" ], "x-maturity": "beta" } }, "/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": "Filter by span attributes as comma-separated key=value pairs, e.g. \"gen_ai.system=openai,gen_ai.request.model=gpt-4\"", "in": "query", "name": "attributes", "required": false, "schema": { "type": "string" } }, { "description": "Filter by span name pattern (ILIKE)", "in": "query", "name": "name_pattern", "required": false, "schema": { "type": "string" } }, { "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" } }, { "description": "Window start (RFC 3339); pair with end_time, max 31 days", "in": "query", "name": "start_time", "required": false, "schema": { "type": "string" } }, { "description": "Window end (RFC 3339); pair with start_time, max 31 days", "in": "query", "name": "end_time", "required": false, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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/features": { "get": { "description": "Always present, in every profile — a client must be able to tell\n\"unavailable here, and here is why\" from \"endpoint does not exist\".", "operationId": "get_platform_features", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlatformFeatures" } } }, "description": "Capabilities of this server process" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" } }, "security": [ { "bearer_auth": [] } ], "summary": "Report which capabilities this server process actually provides.", "tags": [ "Platform" ] } }, "/platform/private-ip": { "get": { "operationId": "get_private_ip", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PrivateIpInfo" } } }, "description": "Successfully retrieved private IP address" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Failed to enumerate network interfaces" } }, "security": [ { "bearer_auth": [] } ], "summary": "Get private/local IP address of the server", "tags": [ "Platform" ] } }, "/platform/public-ip": { "get": { "operationId": "get_public_ip", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublicIpInfo" } } }, "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/PreviewGatewayLogsResponse" } } } }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Docker log request failed" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Preview Gateway" ] } }, "/preview-gateway/restart": { "post": { "operationId": "restart_preview_gateway", "responses": { "204": { "description": "Gateway restarted" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "The gateway is disabled in settings, or another gateway operation is still running" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Gateway restart failed" } }, "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" } } } } }, "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" } } } }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "The container name is not one Docker accepts" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Another gateway operation is still running, or the container name cannot change while this host has sandboxes" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Saving the settings failed, or applying them to the gateway's containers failed" } }, "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" } } } }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Docker status request failed" } }, "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" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "The gateway is disabled in settings, or another gateway operation is still running" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Gateway upgrade failed" } }, "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 (1-100)", "in": "query", "name": "per_page", "required": false, "schema": { "format": "int64", "type": "integer" } }, { "description": "Case-insensitive project name or slug filter", "in": "query", "name": "search", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedProjectList" } } }, "description": "List of projects" }, "400": { "description": "Invalid pagination parameters" }, "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" }, "403": { "description": "Insufficient permissions, or the slug is reserved for host Docker access and only an instance admin may claim it (ADR 045)" }, "409": { "description": "Expected project slug is already in use" }, "428": { "description": "The reserved slug requires a recently MFA-verified session; complete step-up verification and retry (ADR 045)" }, "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/cloudflare-capability": { "get": { "operationId": "get_cloudflare_project_capability", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloudflareProjectCapability" } } } } }, "security": [ { "bearer_auth": [] } ], "summary": "Tell project creators whether Cloudflare is ready and what their new-project default is.", "tags": [ "Projects" ] } }, "/projects/custom-domains/by-host/{hostname}": { "get": { "operationId": "get_visible_custom_domain_by_hostname", "parameters": [ { "description": "Domain hostname", "in": "path", "name": "hostname", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CustomDomainResponse" } } }, "description": "Custom domain assignment retrieved" }, "401": { "description": "Unauthorized" }, "403": { "description": "Project access denied" }, "404": { "description": "Domain is not assigned to a project" } }, "security": [ { "bearer_auth": [] } ], "summary": "Find the project assignment for a certificate hostname.", "tags": [ "Custom Domains" ] } }, "/projects/from-template": { "post": { "description": "Image-backed service templates are created directly from their pinned image.\nSource-backed starter templates can either use their public repository or\ncreate a repository under the selected Git provider account.", "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, or the slug is reserved for host Docker access and only an instance admin may claim it (ADR 045)" }, "404": { "description": "Template not found" }, "428": { "description": "The reserved slug requires a recently MFA-verified session; complete step-up verification and retry (ADR 045)" }, "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" }, "409": { "description": "Project still has CDN delivery bindings; remove them first" }, "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}/alternate-sources": { "patch": { "description": "This leaves `source_type` untouched — a Git project keeps its repository,\nbranch, webhook-driven auto-deploy and rollback rebuild-from-source — and\nonly changes whether the project will additionally accept an uploaded\nsource archive (`drop`). Docker images and static bundles are accepted by\nevery project regardless of this flag.", "operationId": "set_alternate_sources", "parameters": [ { "description": "Project ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetAlternateSourcesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectResponse" } } }, "description": "Alternate-source policy updated" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Project not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Opt a project in or out of accepting deployments from a source other than\nits configured `source_type`.", "tags": [ "Projects" ] } }, "/projects/{id}/compose-security": { "get": { "operationId": "get_compose_security", "parameters": [ { "description": "Project ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ComposeSecurityResponse" } } } }, "403": { "description": "Forbidden" }, "404": { "description": "Project not found" } }, "tags": [ "Projects" ] }, "put": { "operationId": "update_compose_security", "parameters": [ { "description": "Project ID", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateComposeSecurityRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ComposeSecurityResponse" } } } }, "400": { "description": "Invalid settings or missing acknowledgement" }, "403": { "description": "Instance administrator required" }, "404": { "description": "Project not found" }, "409": { "description": "Policy changed; refresh before retrying" } }, "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" ], "x-maturity": "beta" } }, "/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/ActiveVisitorCountResponse" } } }, "description": "Successfully retrieved active visitors count" }, "401": { "description": "Unauthorized" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Get active visitors count", "tags": [ "Events" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "experimental" }, "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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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": [ { "$ref": "#/components/schemas/AgentRunResponse" }, { "type": "null" } ] } } }, "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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" }, "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" ], "x-maturity": "experimental" }, "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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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": [ { "$ref": "#/components/schemas/ConversationResponse" }, { "type": "null" } ] } } } }, "401": {}, "403": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Find the current user's existing chat for a context (returns `null` if none\nyet). Conversations are private even between members of the same project.", "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" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Get-or-create the current user's private chat for a context.", "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" } } } }, "401": {}, "403": {} }, "security": [ { "bearer_auth": [] } ], "summary": "List the current user's active conversations for a project,\nmost-recently-active first.", "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" } }, { "description": "Opaque next_before cursor returned by the previous page", "in": "query", "name": "before", "required": false, "schema": { "type": "string" } }, { "description": "Messages per page (default 50, maximum 100)", "in": "query", "name": "limit", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConversationDetailResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "One bounded conversation-history page (excluding internal context rows).", "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" } } } }, "400": {}, "401": {}, "403": {}, "404": {} }, "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": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Archive (soft-delete) a conversation.", "tags": [ "AI Chat" ] } }, "/projects/{project_id}/ai/conversations/{public_id}/messages": { "post": { "operationId": "send_project_ai_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": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendMessageAcceptedResponse" } } }, "description": "Turn accepted; output follows on the conversation WebSocket" }, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Submit a user message and start a server-owned turn. The command returns as\nsoon as the turn is durable; subscribe to the conversation WebSocket for\nreal-time output.", "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" } } } }, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "List all pending actions for a conversation (most-recently-proposed first).", "tags": [ "AI Chat" ] } }, "/projects/{project_id}/ai/conversations/{public_id}/permission-mode": { "post": { "operationId": "update_permission_mode", "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/UpdatePermissionModeRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConversationResponse" } } } }, "400": {}, "401": {}, "403": {}, "404": {}, "409": {} }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ] } }, "/projects/{project_id}/ai/conversations/{public_id}/permissions/{permission_id}/resolve": { "post": { "operationId": "resolve_permission", "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" } }, { "description": "The CLI's request_id from the SSE event", "in": "path", "name": "permission_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResolvePermissionRequest" } } }, "required": true }, "responses": { "204": { "description": "Decision accepted; subprocess will continue" }, "400": { "description": "Invalid decision payload" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Unknown permission_id (may have timed out or been auto-denied)" }, "409": { "description": "Permission already resolved (concurrent resolve race)" }, "410": { "description": "Turn already ended (subprocess exited before decision arrived)" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Chat" ] } }, "/projects/{project_id}/ai/conversations/{public_id}/stop": { "post": { "operationId": "stop_turn", "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": {}, "401": {}, "403": {}, "404": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Explicitly cancel the server-owned active turn. Closing or refreshing a\nbrowser only detaches its stream; this endpoint is the sole UI cancellation\npath so execution lifetime is not coupled to connectivity.", "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" } } } }, "401": {}, "403": {}, "404": {} }, "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" } } } }, "401": {}, "403": {}, "404": {}, "409": {}, "503": {} }, "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" } } } }, "401": {}, "403": {}, "404": {}, "409": {} }, "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}/ai/structured-output/stream": { "post": { "operationId": "stream_structured_output", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StreamStructuredOutputRequest" } } }, "required": true }, "responses": { "200": { "content": { "text/event-stream": {} }, "description": "SSE events: started, partial, complete, or error" }, "400": { "description": "Invalid prompt or JSON Schema" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "409": { "description": "No active AI provider" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "AI Gateway" ] } }, "/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/bulk": { "post": { "operationId": "bulkUpdateProjectAlarms", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkAlarmRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkAlarmResponse" } } }, "description": "Alarms updated" }, "400": { "description": "Invalid selection or filter" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "An alarm in alarm_ids is not in this project" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Acknowledge or resolve many alarms of a project at once — either the\nexplicit `alarm_ids` or every alarm matching `filter`.", "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}/alarms/{alarm_id}/silence": { "post": { "operationId": "silenceAlarm", "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" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SilenceAlarmRequest" } } }, "required": true }, "responses": { "200": { "description": "Alarm silenced" }, "400": { "description": "Invalid duration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Alarm not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Silence an alarm (and future re-fires of the same type/scope) for a\nchosen duration, without permanently resolving it.", "tags": [ "Alarms" ] } }, "/projects/{project_id}/analytics/activity": { "get": { "operationId": "get_activity_status", "parameters": [ { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "in": "query", "name": "environment_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityStatus" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Visitor Activity" ] }, "put": { "operationId": "save_activity_settings", "parameters": [ { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivitySettings" } } }, "required": true }, "responses": { "204": { "description": "Settings saved" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Visitor Activity" ] } }, "/projects/{project_id}/analytics/activity/goals": { "post": { "operationId": "suggest_activity_goals", "parameters": [ { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityGoalsRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityGoals" } } } }, "400": { "description": "Invalid public URL or consent missing" }, "403": { "description": "Access denied" }, "409": { "description": "Busy" }, "502": { "description": "Site scan or AI suggestion failed" }, "503": { "description": "AI provider missing" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Visitor Activity" ] } }, "/projects/{project_id}/analytics/activity/preview": { "post": { "operationId": "preview_activity_report", "parameters": [ { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityPreviewRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityPreview" } } } }, "400": { "description": "Invalid goal or sharing disabled" }, "403": { "description": "Access denied" }, "404": { "description": "Project not found" }, "409": { "description": "Analysis busy or preview cooling down" }, "502": { "description": "AI preview failed" }, "503": { "description": "AI provider not configured" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Visitor Activity" ] } }, "/projects/{project_id}/analytics/activity/run": { "post": { "operationId": "run_activity_report", "parameters": [ { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityReport" } } } } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Visitor Activity" ] } }, "/projects/{project_id}/analytics/ingest-keys": { "get": { "description": "Includes revoked keys: revocation is soft, and an operator investigating\n\"which key sent this?\" needs to see the rows that no longer work. Every\n`public_key` is returned unmasked — see [`create_analytics_ingest_key`].", "operationId": "list_analytics_ingest_keys", "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/AnalyticsIngestKey" }, "type": "array" } } }, "description": "Ingest keys, active and revoked, newest first" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "List a project's analytics ingest keys, newest first.", "tags": [ "Analytics Ingest Keys" ] }, "post": { "description": "The returned `public_key` is **not a secret**: it is designed to be embedded\nin client-side JavaScript and sent as `X-Temps-Analytics-Key` or\n`?temps_key=`. It is returned in full here and on every subsequent read, so\nan operator can copy it at any time; there is no \"reveal\" step because there\nis nothing to conceal.", "operationId": "create_analytics_ingest_key", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateAnalyticsIngestKeyRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyticsIngestKey" } } }, "description": "Ingest key created" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Project or environment not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Mint a new analytics ingest key.", "tags": [ "Analytics Ingest Keys" ] } }, "/projects/{project_id}/analytics/ingest-keys/{key_id}": { "patch": { "description": "`allowed_origins` and `rate_limit_per_minute` are three-state: omit to leave\nunchanged, send `null` to clear, send a value to replace. Clearing\n`allowed_origins` allows any origin; clearing `rate_limit_per_minute`\nremoves the limit.", "operationId": "update_analytics_ingest_key", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Analytics ingest key ID", "in": "path", "name": "key_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateAnalyticsIngestKeyRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyticsIngestKey" } } }, "description": "Ingest key updated" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Ingest key not found in this project" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Update an ingest key's label, origin allowlist, or rate limit.", "tags": [ "Analytics Ingest Keys" ] } }, "/projects/{project_id}/analytics/ingest-keys/{key_id}/revoke": { "post": { "description": "Soft by design: the row is kept with `is_active = false` and `revoked_at`\nset, so the record of which key ingested what survives. The key stops\nresolving immediately.", "operationId": "revoke_analytics_ingest_key", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Analytics ingest key ID", "in": "path", "name": "key_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "204": { "description": "Ingest key revoked" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Ingest key not found in this project" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Revoke an ingest key.", "tags": [ "Analytics Ingest Keys" ] } }, "/projects/{project_id}/analytics/ingest-keys/{key_id}/rotate": { "post": { "description": "The previous value stops working immediately — the resolution cache entry\nfor it is evicted synchronously rather than left to expire. Any client still\nsending the old value will start receiving 401s, so roll out the new value\nbefore rotating.", "operationId": "rotate_analytics_ingest_key", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Analytics ingest key ID", "in": "path", "name": "key_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyticsIngestKey" } } }, "description": "Ingest key rotated" }, "400": { "description": "The key is revoked and cannot be rotated" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Ingest key not found in this project" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Replace an ingest key's value, keeping the same row and scope.", "tags": [ "Analytics Ingest Keys" ] } }, "/projects/{project_id}/api-analytics/callers": { "get": { "description": "IP addresses are returned as-is from `proxy_logs.client_ip`. The caller\nis responsible for any presentation-layer masking required by their privacy\npolicy.", "operationId": "get_api_callers", "parameters": [ { "description": "Project ID", "in": "path", "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": "Window start (ISO 8601)", "in": "query", "name": "start_date", "required": true, "schema": { "type": "string" } }, { "description": "Window end (ISO 8601)", "in": "query", "name": "end_date", "required": true, "schema": { "type": "string" } }, { "description": "Max callers to return (default: 20, max: 100)", "in": "query", "name": "limit", "required": false, "schema": { "format": "int64", "type": "integer" } }, { "description": "Ranked callers to skip (default: 0)", "in": "query", "name": "offset", "required": false, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiCallersResponse" } } }, "description": "Top callers by request count" }, "400": { "description": "Bad request" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Return the top callers (by client IP, ranked by request count) in a\nproject's API traffic window.", "tags": [ "Analytics" ], "x-maturity": "beta" } }, "/projects/{project_id}/api-analytics/proxy-log-access": { "get": { "operationId": "get_api_traffic_proxy_log_access", "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/ProxyLogAccessResponse" } } }, "description": "Proxy-log drilldown capability" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient analytics permissions" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Project permission check failed" } }, "security": [ { "bearer_auth": [] } ], "summary": "Report whether the current principal may drill into a project's proxy logs.", "tags": [ "Proxy Logs" ], "x-maturity": "beta" } }, "/projects/{project_id}/api-analytics/query": { "post": { "operationId": "aggregate_api_traffic", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrafficAggregationRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrafficAggregationResponse" } } }, "description": "Aggregated API traffic" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Invalid dimensions, metrics, filters, or time range" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Aggregation request budget exceeded" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Storage query failed" }, "504": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Aggregation query timed out" } }, "security": [ { "bearer_auth": [] } ], "summary": "Run a backend-neutral, multi-dimensional API traffic aggregation.", "tags": [ "Proxy Logs" ], "x-maturity": "beta" } }, "/projects/{project_id}/api-analytics/routes": { "get": { "operationId": "get_api_routes", "parameters": [ { "description": "Project ID", "in": "path", "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": "Window start (ISO 8601)", "in": "query", "name": "start_date", "required": true, "schema": { "type": "string" } }, { "description": "Window end (ISO 8601)", "in": "query", "name": "end_date", "required": true, "schema": { "type": "string" } }, { "description": "Max routes to return (default: 20, max: 100)", "in": "query", "name": "limit", "required": false, "schema": { "format": "int64", "type": "integer" } }, { "description": "Ranked routes to skip (default: 0)", "in": "query", "name": "offset", "required": false, "schema": { "format": "int64", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiRoutesResponse" } } }, "description": "Top routes by request count" }, "400": { "description": "Bad request" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Return the top routes (by request count) in a project's API traffic,\ngrouped by raw `(method, path)`.", "tags": [ "Analytics" ], "x-maturity": "beta" } }, "/projects/{project_id}/api-analytics/summary": { "get": { "description": "The response always includes `enabled` and `unavailable_reason` so the\nclient can render a meaningful onboarding state even when no AI provider\nis configured or the project has not opted in. The `summary` field is\nnon-null only when all of the following are true:\n\n- `projects.ai_api_traffic_summary_enabled = true`\n- An AI provider is configured and available\n- The AI call returns parseable JSON within the bounded summary deadline\n\nThis endpoint never returns a 5xx from an AI failure — it always returns\n200 with `summary: null` and a human-readable `unavailable_reason`.", "operationId": "get_api_summary", "parameters": [ { "description": "Project ID", "in": "path", "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": "Window start (ISO 8601)", "in": "query", "name": "start_date", "required": true, "schema": { "type": "string" } }, { "description": "Window end (ISO 8601)", "in": "query", "name": "end_date", "required": true, "schema": { "type": "string" } }, { "description": "Bypass and replace the backend AI summary cache", "in": "query", "name": "refresh", "required": false, "schema": { "type": "boolean" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiTrafficSummaryResponse" } } }, "description": "AI traffic summary (summary field may be null when AI is unavailable)" }, "400": { "description": "Bad request" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error (DB errors only; AI failures return 200 with summary: null)" } }, "security": [ { "bearer_auth": [] } ], "summary": "Return an AI-generated summary of API traffic for the given window.", "tags": [ "Analytics" ], "x-maturity": "beta" } }, "/projects/{project_id}/api-analytics/timeseries": { "get": { "description": "Bucket granularity is auto-selected based on the requested window:\n≤6 h → 5 min, ≤24 h → 1 h, ≤72 h → 6 h, else → 1 day.", "operationId": "get_api_timeseries", "parameters": [ { "description": "Project ID", "in": "path", "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": "Window start (ISO 8601)", "in": "query", "name": "start_date", "required": true, "schema": { "type": "string" } }, { "description": "Window end (ISO 8601)", "in": "query", "name": "end_date", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiTimeseriesResponse" } } }, "description": "Time-series of request volume, errors, and latency" }, "400": { "description": "Bad request" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Return a time-bucketed series of request volume, error rate, and latency\npercentiles for a project's API traffic.", "tags": [ "Analytics" ], "x-maturity": "beta" } }, "/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}/delivery-settings": { "get": { "operationId": "get_project_delivery_settings", "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/ProjectDeliverySettingsResponse" } } }, "description": "Project delivery settings" }, "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": "Project not found" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Project delivery settings. Without DNS provider read access the effective\nprofile is returned in its reduced view (see `GET /delivery-profiles`).", "tags": [ "Traffic Delivery" ] }, "put": { "operationId": "update_project_delivery_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/UpdateProjectDeliverySettingsRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectDeliverySettingsResponse" } } }, "description": "Updated project delivery settings" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Environment belongs to another 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": "Project, environment, or delivery profile not found" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Traffic Delivery" ] } }, "/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}/failure-report": { "get": { "operationId": "get_failure_report_preview", "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": "Failed job ID", "in": "path", "name": "job_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FailureReportPreviewResponse" } } }, "description": "Redacted failure-report preview" }, "404": { "description": "Job not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_token": [] } ], "summary": "Preview a redacted, editable copy of a failed job's trace.", "tags": [ "Deployments" ] }, "post": { "operationId": "send_failure_report", "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": "Failed job ID", "in": "path", "name": "job_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendFailureReportRequest" } } }, "required": true }, "responses": { "204": { "description": "Report sent" }, "404": { "description": "Job not found" }, "422": { "description": "Report text is empty" }, "500": { "description": "Internal server error" }, "502": { "description": "Failed to reach the central reporting endpoint" } }, "security": [ { "bearer_token": [] } ], "summary": "Send a user-reviewed failure report to the Temps team.", "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" } }, { "description": "Return the most recent complete lines (1-100000), reading at most\n8 MiB from local or archived storage. Omit to read the whole log.", "in": "query", "name": "tail", "required": false, "schema": { "maximum": 100000, "minimum": 1, "type": [ "integer", "null" ] } } ], "responses": { "200": { "content": { "text/plain": { "schema": { "type": "string" } } }, "description": "Job logs retrieved successfully" }, "400": { "description": "Invalid tail parameter" }, "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}/domain-delivery-bindings": { "get": { "description": "Newest first by default. `sort_by` accepts `created_at` (default),\n`hostname` or `updated_at`; `sort_order` accepts `asc` or `desc`\n(default), case-insensitive. Binding ID breaks ties in the same direction.\n`page_size` defaults to 20 and is clamped to 1..=100.", "operationId": "list_domain_delivery_bindings", "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" } }, { "description": "Number of items per page (max 100)", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": "string" } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainDeliveryBindingPage" } } }, "description": "One page of the project's domain delivery bindings" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unknown sort_by or sort_order value" }, "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": "Project not found" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "List a project's domain delivery bindings, one page at a time.", "tags": [ "Traffic Delivery" ] } }, "/projects/{project_id}/domain-delivery-bindings/apply": { "post": { "operationId": "apply_domain_delivery_binding", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplyDomainDeliveryBindingRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainDeliveryBindingResponse" } } }, "description": "Delivery binding applied" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Preview expired, stale, or adoption request invalid" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions or preview created by another user" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Preview, project, environment, profile, DNS provider, or managed zone not found" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Routing, DNS records, or the DNS provider or managed zone changed since preview, the project or environment is being deleted, or another operation holds the hostname" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Upstream provider rate limited the request" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" }, "502": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "DNS or CDN provider unreachable or returned an error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Traffic Delivery" ] } }, "/projects/{project_id}/domain-delivery-bindings/preview": { "post": { "operationId": "preview_domain_delivery_binding", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PreviewDomainDeliveryBindingRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainDeliveryPreviewResponse" } } }, "description": "Delivery plan; apply it with the returned preview_id" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Invalid hostname, zone, origin, or profile configuration" }, "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": "Project, environment, profile, DNS provider, or managed zone not found" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Hostname or DNS record is owned by something else" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Upstream provider rate limited the request" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" }, "502": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "DNS or CDN provider unreachable or returned an error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Traffic Delivery" ] } }, "/projects/{project_id}/domain-delivery-bindings/{binding_id}": { "delete": { "operationId": "delete_domain_delivery_binding", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Domain delivery binding ID", "in": "path", "name": "binding_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "204": { "description": "DNS record and binding removed; a Bunny hostname is detached only when Temps added it to the Pull Zone (see bunny_hostname_owned)" }, "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": "Binding not found in this project" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Record is owned by another scope, or another operation holds the hostname" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Upstream provider rate limited the request" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" }, "502": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "DNS or CDN provider unreachable or returned an error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Traffic Delivery" ] } }, "/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 regular plaintext values (audit-logged). Marked secrets\ncannot be revealed.", "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 403 for a manual variable marked secret, and 404 when neither a\nmanual 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": "Regular manual or integration variable value" }, "403": { "description": "Marked secret values are write-only" }, "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/{env_var_id}/detect": { "post": { "operationId": "detectEnvCredential", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Environment variable ID", "in": "path", "name": "env_var_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DetectionView" } } }, "description": "Success" }, "400": { "description": "Invalid configuration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not found" }, "409": { "description": "Check busy" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] } }, "/projects/{project_id}/env-vars/{env_var_id}/history": { "get": { "operationId": "listVariableHistory", "parameters": [ { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "in": "path", "name": "env_var_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "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/VariableHistoryList" } } }, "description": "Variable activity and verification history" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not found" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] } }, "/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": "Regular environment variable value" }, "403": { "description": "Marked secret values are write-only" }, "404": { "description": "Project or variable not found" }, "409": { "description": "Environment variable key is ambiguous" }, "500": { "description": "Internal server error" } }, "summary": "Get a regular environment variable value by key. Marked secrets return 403.", "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-history": { "get": { "operationId": "list_container_history", "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": "Only return containers belonging to this deployment. Omit to list\ncontainers across every deployment the environment has ever had.", "in": "query", "name": "deployment_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "description": "Maximum number of *replaced* container rows to return, most recently\nreplaced first (default 20, max 100). Every currently-running\ncontainer is always included and does not count against this limit —\nit only bounds how much historical (replaced-by-redeploy) context\ncomes back alongside them.", "in": "query", "name": "limit", "required": false, "schema": { "format": "int64", "minimum": 0, "type": [ "integer", "null" ] } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContainerHistoryListResponse" } } }, "description": "Containers that have run for this environment: every currently-running one first (uncapped), then the newest replaced ones up to `limit`" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Environment or deployment not found" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "List every container that has ever run for an environment — current and\nreplaced by a later redeploy. Use each entry's `container_id` (or `id`)\nwith the `/containers/{container_id}/metrics/history` endpoint to fetch\npersisted metrics for a specific container generation, including ones\nthat no longer exist because a redeploy replaced them.", "tags": [ "Deployments" ] } }, "/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" }, "409": { "description": "A container is placed on this process, which has no local Docker daemon" }, "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" }, "409": { "description": "The container is placed on this process, which has no local Docker daemon" }, "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" }, "409": { "description": "The container is placed on this process, which has no local Docker daemon" }, "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" }, "409": { "description": "The container is placed on this process, which has no local Docker daemon" }, "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" }, "409": { "description": "The container is placed on this process, which has no local Docker daemon" }, "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" }, "409": { "description": "The container is placed on this process, which has no local Docker daemon" }, "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" }, "409": { "description": "The container is placed on this process, which has no local Docker daemon" }, "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" }, "409": { "description": "Claiming a local daemon image needs a local Docker daemon, which this process has none of" }, "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": "Deprecated display hint retained for wire compatibility. Temps always\ngenerates the actual project-scoped internal image reference.", "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" ] } }, { "description": "Client-generated UUID identifying this upload attempt. When a\ndeployment already exists for this project, environment, and ID, that\ndeployment is returned as-is instead of importing and deploying the\nimage again — this makes a client retry after a lost response safe.\nCallers that omit it get no such protection (each call always creates\na new deployment), so the CLI always sends one.", "in": "query", "name": "upload_request_id", "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" }, "409": { "description": "Deployment method unavailable in stateless mode" }, "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/image-upload/{upload_request_id}": { "get": { "description": "A client that lost the response to `POST .../deploy/image-upload` (for\nexample, its own wait timed out after the archive was fully sent) can\npoll this endpoint with the same `upload_request_id` it sent on that\nrequest to find out whether the server finished the import and created a\ndeployment, without re-uploading the image. Returns 404 until the\ndeployment exists.", "operationId": "get_deployment_by_upload_request_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": "The upload_request_id sent with the original upload request", "in": "path", "name": "upload_request_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RemoteDeploymentResponse" } } }, "description": "Deployment produced by this upload attempt" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "No deployment found yet for this upload attempt" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Look up the deployment produced by a specific local-image-upload attempt", "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" }, "409": { "description": "Deployment method unavailable in stateless mode" } }, "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" }, "409": { "description": "Deployment method unavailable in stateless mode" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Deploy from an uploaded static bundle", "tags": [ "Deployments" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "beta" }, "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" }, "404": { "description": "Project not found" }, "409": { "description": "Project already holds the maximum number of error alert rules" }, "500": { "description": "Internal server error" } }, "summary": "Create a new alert rule", "tags": [ "error-alert-rules" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" } }, { "description": "Filter chart data to a specific environment.\nAlways AND-combined with project_id — an environment from a different project\nreturns zero-filled buckets rather than cross-project data.", "in": "query", "name": "environment_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } } ], "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" ], "x-maturity": "beta" } }, "/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": "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", "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" } }, { "description": "Include crawler/bot traffic (default: false)", "in": "query", "name": "include_crawlers", "required": false, "schema": { "type": "boolean" } } ], "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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}/http-checks": { "get": { "operationId": "listHttpChecks", "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", "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/HttpCheckList" } } }, "description": "Success" }, "400": { "description": "Invalid configuration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not found" }, "409": { "description": "Check busy" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] }, "post": { "operationId": "createHttpCheck", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SaveHttpCheck" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HttpCheckView" } } }, "description": "Success" }, "400": { "description": "Invalid configuration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not found" }, "409": { "description": "Check busy" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] } }, "/projects/{project_id}/http-checks/capabilities": { "get": { "operationId": "getHttpChecksCapabilities", "parameters": [ { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HttpChecksCapabilities" } } }, "description": "Capabilities" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] } }, "/projects/{project_id}/http-checks/presets": { "get": { "operationId": "listHttpCheckPresets", "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/ProviderPreset" }, "type": "array" } } }, "description": "Success" }, "400": { "description": "Invalid configuration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not found" }, "409": { "description": "Check busy" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] } }, "/projects/{project_id}/http-checks/{check_id}": { "delete": { "operationId": "deleteHttpCheck", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Check ID", "in": "path", "name": "check_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "description": "Success" }, "400": { "description": "Invalid configuration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not found" }, "409": { "description": "Check busy" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] }, "patch": { "operationId": "setHttpCheckEnabled", "parameters": [ { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "in": "path", "name": "check_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetHttpCheckEnabled" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HttpCheckView" } } }, "description": "Updated check" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not found" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] }, "put": { "operationId": "updateHttpCheck", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Check ID", "in": "path", "name": "check_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SaveHttpCheck" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HttpCheckView" } } }, "description": "Success" }, "400": { "description": "Invalid configuration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not found" }, "409": { "description": "Check busy" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] } }, "/projects/{project_id}/http-checks/{check_id}/run": { "post": { "operationId": "runHttpCheck", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "description": "Check ID", "in": "path", "name": "check_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HttpCheckView" } } }, "description": "Success" }, "400": { "description": "Invalid configuration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Not found" }, "409": { "description": "Check busy" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] } }, "/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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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: `request,span,error,revenue`. Empty or\nmissing returns every kind. There is no `log` kind — runtime logs\nintentionally never appear in this feed (see `ObservabilityEvent`'s\n\"No `Log` variant\" doc); passing `kinds=log` is rejected with 400\n`InvalidKindsFilter`, not silently ignored.", "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" } } } } }, "security": [ { "bearer_auth": [] } ], "summary": "Recent ingested events for the activity feed.", "tags": [ "Revenue" ], "x-maturity": "experimental" } }, "/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" } } } } }, "security": [ { "bearer_auth": [] } ], "summary": "List revenue integrations for a project.", "tags": [ "Revenue" ], "x-maturity": "experimental" }, "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" } } } }, "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" ], "x-maturity": "experimental" } }, "/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": {} }, "security": [ { "bearer_auth": [] } ], "summary": "Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).", "tags": [ "Revenue" ], "x-maturity": "experimental" } }, "/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" } } } }, "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" ], "x-maturity": "experimental" } }, "/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" } } } }, "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" ], "x-maturity": "experimental" } }, "/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" } } } }, "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" ], "x-maturity": "experimental" } }, "/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" } } } } }, "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" ], "x-maturity": "experimental" } }, "/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" } } } }, "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" ], "x-maturity": "experimental" } }, "/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" } } } } }, "security": [ { "bearer_auth": [] } ], "summary": "New + churned customers per bucket.", "tags": [ "Revenue" ], "x-maturity": "experimental" } }, "/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" } } } } }, "security": [ { "bearer_auth": [] } ], "summary": "Bucketed MRR timeseries for the revenue chart.", "tags": [ "Revenue" ], "x-maturity": "experimental" } }, "/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" } } } } }, "security": [ { "bearer_auth": [] } ], "summary": "Current MRR / ARR / churn / ARPU for a project, in one currency.", "tags": [ "Revenue" ], "x-maturity": "experimental" } }, "/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}/secrets/{secret_id}/detect": { "post": { "operationId": "detectSecretCredential", "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": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SecretDetectionView" } } }, "description": "Provider candidates and certificate detection; never the value" }, "400": { "description": "Secret is not in this project" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] } }, "/projects/{project_id}/secrets/{secret_id}/history": { "get": { "operationId": "listSecretHistory", "parameters": [ { "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "in": "path", "name": "secret_id", "required": true, "schema": { "format": "int32", "type": "integer" } }, { "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/VariableHistoryList" } } }, "description": "Secret activity and verification history; values are never recorded" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Secret not found" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "HTTP Checks" ] } }, "/projects/{project_id}/service-runtime": { "patch": { "operationId": "update_service_template_runtime", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateServiceTemplateRuntimeRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectResponse" } } }, "description": "Service runtime updated successfully" }, "400": { "description": "Invalid service runtime" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Project not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Projects" ], "x-maturity": "beta" } }, "/projects/{project_id}/service-template": { "get": { "operationId": "get_project_service_template", "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/ServiceTemplateInstanceResponse" } } }, "description": "Applied service release and upgrade preview" }, "400": { "description": "Project is not a service" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Project not found" } }, "security": [ { "bearer_auth": [] } ], "summary": "Return the immutable service-template release applied to a project together\nwith catalog drift, missing requirements, and an available upgrade preview.", "tags": [ "Projects" ], "x-maturity": "beta" } }, "/projects/{project_id}/service-template/upgrade": { "post": { "operationId": "upgrade_project_service_template", "parameters": [ { "description": "Project ID", "in": "path", "name": "project_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpgradeServiceTemplateRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectResponse" } } }, "description": "Service template upgraded" }, "400": { "description": "Invalid or stale upgrade" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden" }, "404": { "description": "Project or template not found" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Projects" ], "x-maturity": "beta" } }, "/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, or the slug being claimed or given up is reserved for host Docker access and only an instance admin may move it (ADR 045)" }, "404": { "description": "Project not found" }, "428": { "description": "The reserved slug requires a recently MFA-verified session; complete step-up verification and retry (ADR 045)" }, "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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" }, "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" ], "x-maturity": "experimental" } }, "/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" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/SourceArchiveUpload" } } }, "required": true }, "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" }, "409": { "description": "Deployment method unavailable in stateless mode" }, "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" ], "x-maturity": "experimental" }, "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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" } }, { "description": "Number of items per page (max 100)", "example": 20, "in": "query", "name": "page_size", "required": false, "schema": { "format": "int64", "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort_by", "required": false, "schema": { "type": "string" } }, { "in": "query", "name": "sort_order", "required": false, "schema": { "type": "string" } } ], "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ] } }, "/projects/{source_project_id}/custom-domains/{domain_id}/assignment": { "put": { "operationId": "reassign_project_custom_domain", "parameters": [ { "description": "Current project ID", "in": "path", "name": "source_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/ReassignCustomDomainRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CustomDomainResponse" } } }, "description": "Domain assignment updated atomically" }, "401": { "description": "Unauthorized" }, "403": { "description": "Write access required for both projects" }, "404": { "description": "Custom domain or target environment not found in the authorized project scopes" }, "409": { "description": "Domain assignment changed; refresh and retry" } }, "security": [ { "bearer_auth": [] } ], "summary": "Move a domain between projects without deleting its route or certificate.", "tags": [ "Custom Domains" ] } }, "/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 an exact request path", "in": "query", "name": "path_exact", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Filter by client IP address", "in": "query", "name": "client_ip", "required": false, "schema": { "type": [ "string", "null" ] } }, { "description": "Exclude Temps status-monitor requests, including legacy monitor rows\nidentified only by their user-agent.", "in": "query", "name": "exclude_synthetic", "required": false, "schema": { "type": [ "boolean", "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": "Project scope for the lookup. Required for non-administrator callers.\nInstance administrators may omit it for legacy global deep links.", "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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 user-traffic health summaries for multiple projects (last 1 hour).\nTemps' own status-monitor requests are excluded.", "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\").\nMust keep `span / interval` ≤ 1000 buckets (7 days at 1 minute is rejected).", "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": "Project scope for the lookup. Required for non-administrator callers.\nInstance administrators may omit it for legacy global deep links.", "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": [ "integer", "null" ] } }, { "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": "Cached default-branch preset slug; __undetected__ means not inspected", "in": "query", "name": "preset", "required": false, "schema": { "type": "string" } }, { "description": "Updated on or after this RFC3339 timestamp", "in": "query", "name": "updated_after", "required": false, "schema": { "type": "string" } }, { "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" }, "403": { "description": "Git provider permission required" }, "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" }, "403": { "description": "Git provider permission required" }, "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}/compose-file/live": { "get": { "operationId": "get_repository_compose_services_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" } }, { "description": "Compose file path to fetch and parse", "in": "query", "name": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RepositoryComposeServicesResponse" } } }, "description": "Compose services parsed successfully" }, "400": { "description": "Bad request, or the compose file could not be parsed" }, "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": [] } ], "summary": "Parse a compose file's services for a connected repository, live", "tags": [ "Git Providers" ] } }, "/repositories/{repository_id}/compose-file/preview": { "post": { "operationId": "get_repository_compose_preview", "parameters": [ { "description": "Repository ID", "in": "path", "name": "repository_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ComposePreviewRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ComposePreviewResponse" } } }, "description": "Effective Compose preview rendered" }, "400": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ComposePreviewProblemResponse" } } }, "description": "Compose file or override is invalid" }, "401": { "description": "Authentication required" }, "404": { "description": "Repository not found" } }, "security": [ { "bearer_auth": [] } ], "summary": "Render a redacted effective Compose preview for a connected repository.", "tags": [ "Git Providers" ] } }, "/repositories/{repository_id}/env-example/live": { "get": { "operationId": "get_repository_env_example_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" } }, { "description": "Project root directory to search (defaults to repository root)", "in": "query", "name": "root_directory", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RepositoryEnvExampleResponse" } } }, "description": "Env-example variables detected (empty if the repository has no env-example file)" }, "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": [] } ], "summary": "Detect and parse a `.env.example`-style file for a connected repository", "tags": [ "Git Providers" ] } }, "/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" }, "403": { "description": "Git provider permission required" }, "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" }, "403": { "description": "Git provider permission required" }, "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" }, "403": { "description": "Git provider permission required" }, "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" }, "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": "Restore run not found" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Restore" ] } }, "/restore-runs/{id}/cancel": { "post": { "operationId": "cancel_restore_run", "parameters": [ { "description": "Restore run id", "in": "path", "name": "id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestoreRunView" } } }, "description": "Cancellation recorded (or already recorded); the run stops at its next check and ends as `cancelled`" }, "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": "Restore run not found" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Conflict: the run already finished (`restore-not-active`, with `run_status`), or it can no longer be stopped safely (`restore-not-cancellable`, with `phase`): an in-place restore has started writing data, or a new service is being registered" } }, "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" } } } } }, "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" ], "x-maturity": "experimental" } }, "/revenue/metrics/global-mrr": { "get": { "operationId": "revenue_metrics_global_mrr", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalMrrResponse" } } } } }, "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" ], "x-maturity": "experimental" } }, "/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" } } } } }, "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" ], "x-maturity": "experimental" } }, "/revenue/providers": { "get": { "operationId": "revenue_list_providers", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ProviderDescriptor" }, "type": "array" } } } } }, "security": [ { "bearer_auth": [] } ], "summary": "List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).", "tags": [ "Revenue" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "beta" } }, "/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", "parameters": [ { "description": "Return only static/cached catalog metadata. This path deliberately\nskips the settings-row read as well as CLI probes and is used for chat\nfirst paint; an authenticated refresh follows in the background.", "in": "query", "name": "catalog_only", "required": false, "schema": { "type": "boolean" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderCatalogResponse" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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/ai-providers/{provider_id}/credential/import-local": { "post": { "operationId": "import_local_ai_provider_credential", "parameters": [ { "description": "AI provider ID", "in": "path", "name": "provider_id", "required": true, "schema": { "type": "string" } }, { "description": "OpenCode model to use for the verification request, in `provider/model` form.", "in": "query", "name": "verification_model", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportLocalCredentialResponse" } } } }, "400": { "description": "Unknown provider or invalid local credential" }, "401": { "description": "Unauthorized" }, "403": { "description": "System administrator permission required" }, "404": { "description": "No importable local credential found" } }, "security": [ { "bearer_auth": [] } ], "summary": "Import the credential already used by this provider's CLI on the Temps\nhost. Discovery and encryption happen entirely server-side; the plaintext\ncredential is never serialized into the response or browser state.", "tags": [ "Agents" ] } }, "/settings/ai-providers/{provider_id}/credential/verify-saved": { "post": { "operationId": "verify_saved_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/VerifySavedCredentialRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SaveCredentialResponse" } } } }, "400": { "description": "Invalid model or credential rejected" }, "404": { "description": "No saved credential" } }, "security": [ { "bearer_auth": [] } ], "summary": "Verify a previously imported OpenCode credential against a user-selected\nmodel without asking the browser to receive or resubmit the secret.", "tags": [ "Agents" ] } }, "/settings/ai-providers/{provider_id}/models/refresh": { "post": { "operationId": "refresh_ai_provider_models", "parameters": [ { "description": "AI provider ID", "in": "path", "name": "provider_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshProviderModelsResponse" } } } }, "400": { "description": "Unknown provider" }, "401": { "description": "Unauthorized" }, "403": { "description": "Provider execution permission required" }, "503": { "description": "Provider model discovery unavailable" } }, "security": [ { "bearer_auth": [] } ], "summary": "Refresh exactly one provider's account-aware model inventory. This is an\nexplicit operation because it starts a CLI process (and, for Claude\nworkspaces, creates or wakes the user's persistent sandbox). Authorization\ntherefore matches the provider's chat execution requirement instead of\nrequiring unrelated settings mutation access. The AI service applies a\nprovider-scoped single-flight and cooldown before doing that work.", "tags": [ "Agents" ] } }, "/settings/ai-providers/{provider_id}/preflight": { "post": { "operationId": "run_ai_provider_preflight", "parameters": [ { "description": "AI provider ID", "in": "path", "name": "provider_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HarnessCheckReport" } } } }, "400": { "description": "Unknown provider" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Another diagnostic is running" }, "503": { "description": "Diagnostic unavailable" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Agents" ] } }, "/settings/ai-providers/{provider_id}/smoke": { "post": { "operationId": "run_ai_provider_smoke", "parameters": [ { "description": "AI provider ID", "in": "path", "name": "provider_id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HarnessSmokeRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HarnessCheckReport" } } } }, "400": { "description": "Consent required or unknown provider" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Another diagnostic is running" }, "503": { "description": "Diagnostic unavailable" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Agents" ] } }, "/settings/cluster-ca/rotate": { "post": { "operationId": "rotate_cluster_ca", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RotateClusterCaRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RotateClusterCaResponse" } } }, "description": "Cluster CA rotated" }, "400": { "description": "Invalid confirmation or CA state" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "409": { "description": "Expected fingerprint is stale" }, "428": { "description": "Fresh MFA verification required" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Replace a compromised cluster CA and invalidate outstanding enrollment\ntokens. Existing workers fail closed until they are re-enrolled.", "tags": [ "Settings" ] } }, "/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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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" } } } }, "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/telemetry": { "get": { "description": "Reports whether this server sends anonymous product telemetry, what decided\nit (environment kill switch, admin setting or default), the random instance\nID, the destination host, and every event type the binary can send.", "operationId": "get_telemetry_settings", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TelemetryStatusResponse" } } }, "description": "Current telemetry state" }, "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": "Stored preference could not be read" } }, "security": [ { "bearer_auth": [] } ], "summary": "Anonymous telemetry status and disclosure", "tags": [ "Telemetry" ] }, "patch": { "description": "Instance admins only. Persisted in the settings row, audit-logged as\n`TELEMETRY_SETTING_UPDATED`, and applied without a restart. When\n`TEMPS_TELEMETRY` forces telemetry off, the choice is still saved but has\nno effect until the variable is removed; the response says so via\n`source = environment`.", "operationId": "update_telemetry_settings", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateTelemetrySettingsRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TelemetryStatusResponse" } } }, "description": "Setting saved; returns the new state" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Invalid request body" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Instance admin required" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Setting could not be saved" } }, "security": [ { "bearer_auth": [] } ], "summary": "Turn anonymous telemetry on or off", "tags": [ "Telemetry" ] } }, "/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", "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" ] } }, "/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" ] } }, "/system/alarms": { "get": { "operationId": "listSystemAlarms", "parameters": [ { "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 system alarms" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "List host/control-plane-wide alarms with optional filters.", "tags": [ "Alarms" ] } }, "/system/alarms/bulk": { "post": { "operationId": "bulkUpdateSystemAlarms", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkAlarmRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkAlarmResponse" } } }, "description": "Alarms updated" }, "400": { "description": "Invalid selection or filter" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "An alarm in alarm_ids is not a system alarm" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Acknowledge or resolve many system alarms at once — either the explicit\n`alarm_ids` or every system alarm matching `filter`.", "tags": [ "Alarms" ] } }, "/system/alarms/summary": { "get": { "operationId": "getSystemAlarmsSummary", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AlarmSummaryResponse" } } }, "description": "System 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 system alarms (dashboard summary widget).", "tags": [ "Alarms" ] } }, "/system/alarms/{alarm_id}/acknowledge": { "post": { "operationId": "acknowledgeSystemAlarm", "parameters": [ { "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 system alarm.", "tags": [ "Alarms" ] } }, "/system/alarms/{alarm_id}/resolve": { "post": { "operationId": "resolveSystemAlarm", "parameters": [ { "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 a system alarm.", "tags": [ "Alarms" ] } }, "/system/alarms/{alarm_id}/silence": { "post": { "operationId": "silenceSystemAlarm", "parameters": [ { "description": "Alarm ID", "in": "path", "name": "alarm_id", "required": true, "schema": { "format": "int32", "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SilenceAlarmRequest" } } }, "required": true }, "responses": { "200": { "description": "Alarm silenced" }, "400": { "description": "Invalid duration" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Alarm not found" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Silence a system alarm (and future re-fires of the same type/scope) for a\nchosen duration, without permanently resolving it.", "tags": [ "Alarms" ] } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" } }, { "description": "Filter by gallery: starter or service", "in": "query", "name": "kind", "required": false, "schema": { "$ref": "#/components/schemas/TemplateKind" } } ], "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" ] } }, "/traefik-discovery/routes": { "get": { "operationId": "list_traefik_discovered_routes", "parameters": [ { "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/TraefikDiscoveredRouteListResponse" } } }, "description": "Discovered routes and unresolved host conflicts" }, "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 every container adopted from Traefik labels, plus the labelled\ncontainers that were found and rejected.", "tags": [ "Traefik Discovery" ] } }, "/traefik-discovery/routes/{host}/certificate": { "delete": { "description": "Clears `cert_authorized` so Temps stops attempting renewal. Does **not**\ndelete the `domains` row or the certificate — deleting live key material as\na side effect of deauthorization is the kind of surprise this codebase\navoids. Use `DELETE /domains/{host}` to remove the certificate itself.", "operationId": "deauthorize_discovered_route_cert", "parameters": [ { "description": "Hostname of the discovered route", "in": "path", "name": "host", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "TLS authorization cleared" }, "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 authorization record for that host" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Remove TLS authorization for a discovered route.", "tags": [ "Traefik Discovery" ] }, "post": { "description": "The operator explicitly authorizes issuance; `cert_eligible` stays `false`\nso the container's own labels can never trigger this. Both `SettingsWrite`\nand `DomainsCreate` are required: `SettingsWrite` is Admin/PlatformAdmin\nonly, so any caller reaching this endpoint is already an administrator.\n\nThe authorization is recorded against the container identity currently\nserving the host (§2a). Container drift after authorization fires a Critical\nalarm but does not auto-clear `cert_authorized` — auto-clearing would not\nremove the certificate and would be a DoS primitive (ADR-041 §2a).", "operationId": "request_discovered_route_cert", "parameters": [ { "description": "Hostname of the discovered route", "in": "path", "name": "host", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RequestDiscoveredRouteCertRequest" } } }, "required": true }, "responses": { "201": { "description": "TLS authorization created and ACME challenge initiated" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Validation error (e.g. unsupported challenge_type)" }, "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 discovered route for that host" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Host owned by another resource, or verification_method conflict" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Certificate validation failed" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" }, "502": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "TLS provisioner error (ACME upstream failure)" } }, "security": [ { "bearer_auth": [] } ], "summary": "Request Temps to issue an ACME certificate for a discovered route (Path A).", "tags": [ "Traefik Discovery" ] } }, "/traefik-discovery/routes/{host}/enabled": { "patch": { "description": "This is a plain column update: the `traefik_discovered_routes` row-level\ntrigger fires `notify_route_table_change()` on an `enabled` change, so the\nexisting `route_table_changes` LISTEN/NOTIFY path reloads this node's route\ntable *and* every other control plane node's. No manual reload here.", "operationId": "set_traefik_discovered_route_enabled", "parameters": [ { "description": "Hostname of the discovered route", "in": "path", "name": "host", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateTraefikRouteEnabledRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TraefikDiscoveredRouteResponse" } } }, "description": "Updated discovered route" }, "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": "No discovered route for that host" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Suppress or restore a single discovered route.", "tags": [ "Traefik Discovery" ] } }, "/traefik-discovery/status": { "get": { "operationId": "get_traefik_discovery_status", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TraefikDiscoveryStatusResponse" } } }, "description": "Discovery status. `configured: false` means it is not turned on here — the `setup` block says exactly how to turn it on" }, "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": "Whether Traefik label discovery is active on this instance, and how to turn\nit on when it is not.", "tags": [ "Traefik Discovery" ] } }, "/traefik-discovery/tls/import": { "post": { "description": "Upload the raw contents of Traefik's `acme.json` and a list of hosts to\nimport. Each host is independently validated (8-step chain from ADR-041 §5)\nand a per-host verdict is returned. `dry_run: true` runs all validation\nwithout writing anything, so the operator can preview before committing.\n\nThe request body is capped at 1 MiB. Do **not** add a decompression layer\nto this route — the 1 MiB cap's security properties depend on the absence\nof decompression here (ADR-041 §4).", "operationId": "import_traefik_acme_json", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportTraefikAcmeJsonRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportTraefikAcmeJsonResponse" } } }, "description": "Import results (per-host verdicts)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Validation error (malformed JSON, unsupported renewal_method)" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Unauthorized" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Insufficient permissions" }, "413": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Request body exceeds the 1 MiB limit" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } }, "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Import certificates from a Traefik `acme.json` document (Path B).", "tags": [ "Traefik Discovery" ] } }, "/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", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetupMfaRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MfaSetupResponse" } } }, "description": "MFA setup data" }, "400": { "description": "Current password is required but was not provided" }, "401": { "description": "Unauthorized or current password is incorrect" }, "409": { "description": "MFA is already enabled; verify and disable it before re-enrollment" }, "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}/password": { "post": { "description": "The recovery path for a user who lost their password when outbound email\nis not configured. Every browser session of the user is revoked and they\nmust choose a new password at next sign-in. API keys are deliberately left\nalone, matching `POST /users/me/password`: revoking them would silently\nbreak the user's automation. The temporary password is returned once and\ncannot be retrieved again.\n\nAny `users:manage` principal may reset any other user, including another\nadmin. That is the existing trust model for this permission (it can already\ndelete users and change their roles); only resetting yourself is refused.", "operationId": "reset_user_password", "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/ResetUserPasswordResponse" } } }, "description": "Password reset; the temporary password is returned once" }, "401": { "description": "Unauthorized" }, "403": { "description": "users:manage required, or attempted to reset your own password (use POST /users/me/password)" }, "404": { "description": "User not found" }, "409": { "description": "User is deleted" }, "428": { "description": "Recent identity verification (step-up) required" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "summary": "Reset another user's password to a generated temporary one (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/platform/feature-maturity": { "get": { "operationId": "get_feature_maturity", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/FeatureMaturity" }, "type": "array" } } }, "description": "Feature maturity registry for this build" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" } }, "security": [ { "bearer_auth": [] } ], "summary": "Return the build-time compatibility promise for every user-facing feature.", "tags": [ "Platform" ] } }, "/v1/sandbox-snapshots": { "get": { "operationId": "list_snapshots", "parameters": [ { "description": "Filter by project", "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": "integer" } }, { "description": "Filter by status", "in": "query", "name": "status", "required": false, "schema": { "type": "string" } }, { "description": "Page number (1-indexed)", "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/ListSnapshotsResponse" } } }, "description": "List of snapshots" }, "401": { "description": "Unauthorized" } }, "security": [ { "bearer_auth": [] } ], "summary": "`GET /v1/sandbox-snapshots`", "tags": [ "Snapshots" ], "x-maturity": "experimental" } }, "/v1/sandbox-snapshots/storage-summary": { "get": { "operationId": "storage_summary", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StorageSummary" } } }, "description": "Storage usage summary" }, "401": { "description": "Unauthorized" } }, "security": [ { "bearer_auth": [] } ], "summary": "`GET /v1/sandbox-snapshots/storage-summary`", "tags": [ "Snapshots" ], "x-maturity": "experimental" } }, "/v1/sandbox-snapshots/{snap_id}": { "delete": { "operationId": "delete_snapshot", "parameters": [ { "description": "Snapshot public ID", "in": "path", "name": "snap_id", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Snapshot deleted" }, "401": { "description": "Unauthorized" }, "404": { "description": "Not found" }, "500": { "description": "Internal error" } }, "security": [ { "bearer_auth": [] } ], "summary": "`DELETE /v1/sandbox-snapshots/{snap_id}`", "tags": [ "Snapshots" ], "x-maturity": "experimental" }, "get": { "operationId": "get_snapshot", "parameters": [ { "description": "Snapshot public ID", "in": "path", "name": "snap_id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SnapshotResponse" } } }, "description": "Snapshot detail" }, "401": { "description": "Unauthorized" }, "404": { "description": "Not found" } }, "security": [ { "bearer_auth": [] } ], "summary": "`GET /v1/sandbox-snapshots/{snap_id}`", "tags": [ "Snapshots" ], "x-maturity": "experimental" } }, "/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" } }, { "description": "Filter by lifecycle class: \"ephemeral\" or \"workspace\"", "in": "query", "name": "lifecycle", "required": false, "schema": { "type": "string" } }, { "description": "Filter to sandboxes created from a project", "in": "query", "name": "project_id", "required": false, "schema": { "format": "int32", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListSandboxesResponse" } } }, "description": "List sandboxes" }, "400": { "description": "Unknown lifecycle value" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Sandboxes" ], "x-maturity": "experimental" }, "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" }, "422": { "description": "Requested node does not exist, is not allowed to run sandboxes, is not active, or no node is eligible" }, "500": { "description": "Internal server error" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Sandboxes" ], "x-maturity": "experimental" } }, "/v1/sandboxes/placement": { "get": { "operationId": "get_sandbox_placement", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SandboxPlacementResponse" } } }, "description": "Sandbox placement state" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" } }, "security": [ { "bearer_auth": [] } ], "summary": "List the nodes sandboxes can be placed on and the operator allow-list.", "tags": [ "Sandboxes" ], "x-maturity": "experimental" }, "put": { "operationId": "update_sandbox_placement", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateSandboxPlacementBody" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SandboxPlacementResponse" } } }, "description": "Updated placement state" }, "400": { "description": "Unknown or duplicate node id, or `allowed_node_ids` missing (send `null` to allow every node)" }, "401": { "description": "Unauthorized" }, "403": { "description": "Administrator role required" } }, "security": [ { "bearer_auth": [] } ], "summary": "Set which nodes may run new sandboxes. Admin only.", "tags": [ "Sandboxes" ], "x-maturity": "experimental" } }, "/v1/sandboxes/placement/nodes/{node}": { "get": { "operationId": "list_node_sandboxes", "parameters": [ { "description": "Worker name or id, or `control-plane` / `0`", "in": "path", "name": "node", "required": true, "schema": { "type": "string" } }, { "description": "1-based page (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/NodeSandboxesResponse" } } }, "description": "Sandboxes on the node" }, "401": { "description": "Unauthorized" }, "403": { "description": "Administrator role required" }, "404": { "description": "No such node" } }, "security": [ { "bearer_auth": [] } ], "summary": "List every live sandbox on one node, from all owners. Admin only: it\nexposes other users' sandboxes.", "tags": [ "Sandboxes" ], "x-maturity": "experimental" } }, "/v1/sandboxes/placement/nodes/{node}/evict": { "post": { "operationId": "evict_node_sandboxes", "parameters": [ { "description": "Worker name or id", "in": "path", "name": "node", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeEvictionResponse" } } }, "description": "Sandboxes destroyed" }, "400": { "description": "The control plane cannot be evicted" }, "401": { "description": "Unauthorized" }, "403": { "description": "Administrator role required" }, "404": { "description": "No such worker node" }, "409": { "description": "An eviction of this node is already running" }, "428": { "description": "Recent MFA verification required (browser sessions)" }, "503": { "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/NodeEvictionIncompleteProblem" } } }, "description": "Some sandboxes could not be destroyed; `destroyed`, `containers_unconfirmed` and `failed` list them, and retrying picks the failed ones up" } }, "security": [ { "bearer_auth": [] } ], "summary": "Destroy every live sandbox on a worker node, from all owners, so the node\ncan be removed. Works on a node that is offline for good: its sandboxes\nare marked destroyed even when the node cannot be reached. Admin only.", "tags": [ "Sandboxes" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" }, "503": { "description": "The sandbox's worker node is unreachable; the sandbox was kept" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Sandboxes" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" }, "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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/v1/sandboxes/{id}/runtime-environment": { "post": { "operationId": "sandbox_issue_runtime_environment", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SandboxRuntimeEnvironmentResponse" } } }, "description": "Runtime variables issued" }, "400": { "description": "Sandbox has no attached project" }, "403": { "description": "Plaintext secret access is not permitted" }, "404": { "description": "Sandbox or project environment not found" }, "409": { "description": "Linked services expose ambiguous variables" }, "503": { "description": "Runtime credential provider unavailable" } }, "security": [ { "bearer_auth": [] } ], "summary": "Issue the same scoped service variables used by a deployment runtime for\nthe project attached to this sandbox.", "tags": [ "Sandboxes" ], "x-maturity": "experimental" } }, "/v1/sandboxes/{id}/snapshots": { "post": { "description": "Initiates a snapshot of the sandbox. The response is **202 Accepted**\nwith the snapshot row in `creating` status. The caller should poll\n`GET /v1/sandbox-snapshots/{snap_id}` until `status` is `ready` or\n`failed`.\n\nThe sandbox is stopped for the duration of the snapshot and restarted\nautomatically when it completes (unless it was already stopped).", "operationId": "create_snapshot", "parameters": [ { "description": "Sandbox public ID", "in": "path", "name": "id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateSnapshotBody" } } }, "required": true }, "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SnapshotResponse" } } }, "description": "Snapshot initiated" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Sandbox not found" }, "422": { "description": "Quota exceeded or invalid state" }, "500": { "description": "Internal error" }, "501": { "description": "Snapshots not supported by backend" } }, "security": [ { "bearer_auth": [] } ], "summary": "`POST /v1/sandboxes/{id}/snapshots`", "tags": [ "Snapshots" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" }, "503": { "description": "The sandbox's worker node is unreachable; the sandbox was kept" } }, "security": [ { "bearer_auth": [] } ], "tags": [ "Sandboxes" ], "x-maturity": "experimental" } }, "/v1/sandboxes/{id}/terminal": { "get": { "operationId": "terminal", "parameters": [ { "description": "Sandbox public ID", "in": "path", "name": "id", "required": true, "schema": { "type": "string" } }, { "description": "Tab to attach to (default \"main\"); reusing an id reattaches to the running program", "in": "query", "name": "tab", "required": false, "schema": { "type": "string" } }, { "description": "Program to launch when the tab is created (default: login shell)", "in": "query", "name": "cmd", "required": false, "schema": { "type": "string" } }, { "description": "Initial columns (default 80)", "in": "query", "name": "cols", "required": false, "schema": { "format": "int32", "minimum": 0, "type": "integer" } }, { "description": "Initial rows (default 24)", "in": "query", "name": "rows", "required": false, "schema": { "format": "int32", "minimum": 0, "type": "integer" } } ], "responses": { "101": { "description": "WebSocket established; PTY attached" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" }, "404": { "description": "Sandbox not found" }, "409": { "description": "Sandbox is not in a state that can be attached to" } }, "security": [ { "bearer_auth": [] } ], "summary": "Attach an interactive terminal to a sandbox.", "tags": [ "Sandboxes" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "beta" }, "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" ], "x-maturity": "beta" } }, "/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" ], "x-maturity": "experimental" }, "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" ], "x-maturity": "experimental" } }, "/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" ], "x-maturity": "experimental" } }, "/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" ] } }, "/{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, ISO 8601 (e.g. \"2024-01-15T14:30:00Z\")", "example": "2024-01-15T14:30:00Z", "in": "query", "name": "from", "required": false, "schema": { "format": "date-time", "type": "string" } }, { "description": "End timestamp, ISO 8601 (e.g. \"2024-01-15T14:30:00Z\")", "example": "2024-01-15T14:30:00Z", "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": "Anonymous product telemetry status and opt-out", "name": "Telemetry" }, { "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": "Severity routing from notifications to providers", "name": "Notification Routes" }, { "description": "User notification preferences and settings", "name": "Notification Preferences" }, { "description": "DNS provider management endpoints", "name": "DNS Providers" }, { "description": "Ownership-guarded managed DNS records (ADR-031)", "name": "DNS Records" }, { "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": "Recent and in-flight operations across projects", "name": "Operations" }, { "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": "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": "Gateway capability and summary-default endpoints", "name": "AI Provider Status" }, { "description": "Manage non-secret analytics ingest keys for apps Temps does not deploy", "name": "Analytics Ingest Keys" }, { "description": "AI interpretation of recent visitor activity", "name": "Visitor Activity" }, { "description": "Cron jobs management API", "name": "Crons" }, { "description": "Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers.", "name": "Sandboxes" }, { "description": "Sandbox snapshot API (ADR-037): create, list, get, and delete snapshots.", "name": "Snapshots" }, { "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": "Span attribute facet registration (fast-filter slots)", "name": "OTel Facets" }, { "description": "GenAI agent activity tracing endpoints", "name": "GenAI" }, { "description": "Unified alarm history — list, summarise, acknowledge, resolve", "name": "Alarms" }, { "description": "Credential checks for environment variables and secrets: provider HTTP verification and local expiry of certificates, SSH certificates, OpenPGP keys, kubeconfigs and JWTs", "name": "HTTP Checks" }, { "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": "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" } ] }