{"openapi":"3.1.0","servers":[{"url":"https://api.spice.ai"}],"info":{"title":"Spice Cloud Control-Plane API","version":"v1","description":"The Spice Cloud Platform API provides programmatic access to manage apps, deployments, secrets, API keys, and organization members on the Spice.ai cloud platform."},"paths":{"/v1/health":{"get":{"summary":"Health check","description":"Returns the health status of the API.","responses":{"200":{"description":"API is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"timestamp":{"type":"string","format":"date-time"}}}}}}},"tags":["Health"]}},"/v1/apps":{"get":{"summary":"List apps","description":"Returns all apps belonging to the authenticated organization.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"List of apps","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/App"}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"}},"tags":["Apps"]},"post":{"summary":"Create an app","description":"Creates a new app in the authenticated organization.","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":4,"pattern":"^[a-zA-Z0-9-]+$","description":"App name (letters, numbers, hyphens only)"},"region":{"type":"string","enum":["us-east-1","us-west-2"],"description":"Cloud region where the app will be deployed (e.g. `us-east-1`).\n"},"cname":{"type":"string","description":"**Deprecated.** Internal region CNAME (e.g. `us-east-1-prod-aws-data`). Use `region` instead. Accepted for backwards compatibility when `region` is omitted.\n"},"description":{"type":"string","description":"App description"},"visibility":{"type":"string","enum":["public","private"],"default":"private"},"tags":{"type":"object","additionalProperties":{"type":"string"},"description":"Key-value tags for the app"},"update_channel":{"type":"string","enum":["stable","preview","nightly","internal"],"description":"Update channel for the app deployment"},"replicas":{"type":"integer","minimum":0,"description":"Number of replicas"},"resources":{"type":"object","description":"Resource requests and limits for the app container","properties":{"limits":{"type":"object","properties":{"cpu":{"type":"string","description":"Whole-number vCPU limit, or '-' for no CPU limit"},"memory":{"type":"string","description":"Memory limit in Gi (for example, 16Gi)"},"ephemeral-storage":{"type":"string","description":"Ephemeral storage limit in Gi (for example, 8Gi)"}}},"requests":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"}}}}},"executor":{"type":"object","description":"Executor container configuration","properties":{"replicas":{"type":"integer","minimum":0,"description":"Number of executor replicas"},"resources":{"type":"object","description":"Resource requests and limits for the executor container","properties":{"limits":{"type":"object","properties":{"cpu":{"type":"string","description":"Whole-number vCPU limit, or '-' for no CPU limit"},"memory":{"type":"string","description":"Memory limit in Gi (for example, 16Gi)"},"ephemeral-storage":{"type":"string","description":"Ephemeral storage limit in Gi (for example, 8Gi)"}}},"requests":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"}}}}}}}}}}}},"responses":{"201":{"description":"App created successfully. The response may include a `warning` field if initial configuration could not be applied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppWithConfig"}}}},"400":{"description":"Invalid request body or invalid region"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, organization app limit exceeded, or private compute addon required for resource limits"},"409":{"description":"An app with this name already exists"}},"tags":["Apps"]}},"/v1/apps/{appId}":{"get":{"summary":"Get an app","description":"Returns details for a specific app, including its configuration.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"}],"responses":{"200":{"description":"App details with configuration","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]},"created_at":{"type":"string","format":"date-time"},"region":{"type":"string"},"production_branch":{"type":"string"},"api_key":{"type":"string","deprecated":true,"description":"Deprecated. Use the API Keys endpoints instead."},"tags":{"type":"object","additionalProperties":{"type":"string"}},"config":{"type":"object","properties":{"spicepod":{"type":"object"},"image_tag":{"type":"string","description":"Runtime image tag"},"update_channel":{"type":"string","enum":["stable","preview","nightly","internal"],"description":"Update channel for the runtime"},"replicas":{"type":"integer"},"resources":{"type":"object","nullable":true,"description":"Resource requests and limits for the app container","properties":{"limits":{"type":"object","properties":{"cpu":{"type":"string","description":"Whole-number vCPU limit, or '-' for no CPU limit"},"memory":{"type":"string","description":"Memory limit in Gi (for example, 16Gi)"},"ephemeral-storage":{"type":"string"}}},"requests":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"}}}}},"executor":{"type":"object","nullable":true,"description":"Executor container configuration","properties":{"replicas":{"type":"integer","description":"Number of executor replicas"},"resources":{"type":"object","description":"Resource requests and limits for the executor container","properties":{"limits":{"type":"object","properties":{"cpu":{"type":"string","description":"Whole-number vCPU limit, or '-' for no CPU limit"},"memory":{"type":"string","description":"Memory limit in Gi (for example, 16Gi)"},"ephemeral-storage":{"type":"string"}}},"requests":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"}}}}},"storage_size_gb":{"type":"number","nullable":true}}},"region":{"type":"string"},"storage_size_gb":{"type":"number","nullable":true},"storage_claim_size_gb":{"type":"number","deprecated":true,"description":"Deprecated. Use storage_size_gb instead."}}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App not found"},"500":{"description":"Internal server error"}},"tags":["Apps"]},"put":{"summary":"Update an app","description":"Updates an app's metadata and configuration, including description, visibility, spicepod configuration, replicas, and resource limits.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]},"production_branch":{"type":"string"},"tags":{"type":"object","additionalProperties":{"type":"string"},"description":"Key-value tags for the app"},"spicepod":{"oneOf":[{"type":"string","description":"YAML string of the spicepod configuration"},{"type":"object","description":"JSON object of the spicepod configuration"}]},"image_tag":{"type":"string","description":"Runtime image tag"},"update_channel":{"type":"string","enum":["stable","preview","nightly","internal"],"description":"Update channel for the runtime"},"replicas":{"type":"integer","minimum":0},"resources":{"type":"object","description":"Resource requests and limits for the app container","properties":{"limits":{"type":"object","properties":{"cpu":{"type":"string","description":"Whole-number vCPU limit, or '-' for no CPU limit"},"memory":{"type":"string","description":"Memory limit in Gi (for example, 16Gi)"},"ephemeral-storage":{"type":"string","description":"Ephemeral storage limit in Gi (for example, 8Gi)"}}},"requests":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"}}}}},"executor":{"type":"object","description":"Executor container configuration","properties":{"replicas":{"type":"integer","minimum":0,"description":"Number of executor replicas"},"resources":{"type":"object","description":"Resource requests and limits for the executor container","properties":{"limits":{"type":"object","properties":{"cpu":{"type":"string","description":"Whole-number vCPU limit, or '-' for no CPU limit"},"memory":{"type":"string","description":"Memory limit in Gi (for example, 16Gi)"},"ephemeral-storage":{"type":"string","description":"Ephemeral storage limit in Gi (for example, 8Gi)"}}},"requests":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"}}}}},"storage_size_gb":{"type":"number"}}},"region":{"type":"string"},"storage_size_gb":{"type":"number"},"storage_claim_size_gb":{"type":"number","deprecated":true,"description":"Deprecated. Use storage_size_gb instead."}}}}}},"responses":{"200":{"description":"App updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppWithConfig"}}}},"400":{"description":"Invalid request body or app ID"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, requested replicas or resources exceed plan limits, or private compute addon is required"},"404":{"description":"App not found"},"500":{"description":"Internal server error"}},"tags":["Apps"]},"delete":{"summary":"Delete an app","description":"Deletes an app and tears down its runtime resources.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app to delete"}],"responses":{"204":{"description":"App deleted successfully"},"400":{"description":"Invalid app ID"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App not found"},"500":{"description":"Internal server error"}},"tags":["Apps"]}},"/v1/apps/{appId}/metrics":{"get":{"summary":"Get app metrics","description":"Returns current resource utilization metrics (CPU, memory, disk I/O) and data ingestion metrics for an app.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"},{"in":"query","name":"window","required":false,"schema":{"type":"string"},"description":"Prometheus-style duration (e.g. `5m`, `1h`, `30s`). When provided, counter metrics are returned as rates over the window instead of raw cumulative values. For example, `rows_ingested` returns average rows per second with a window, or total cumulative rows without one."}],"responses":{"200":{"description":"Resource and ingestion metrics. Missing fields indicate no data is currently available. Individual metric queries may fail independently; partial results are returned when possible.","content":{"application/json":{"schema":{"type":"object","properties":{"ingestion":{"type":"object","description":"Aggregated data ingestion metrics","properties":{"rows_ingested":{"type":"number","description":"Total rows ingested (without window) or rows per second (with window)"},"bytes_ingested":{"type":"number","description":"Total bytes ingested (without window) or bytes per second (with window)"}}},"cluster":{"type":"object","description":"Cluster metrics for the app","properties":{"active_executors_count":{"type":"number","description":"Number of active executors registered with the scheduler"}}},"metrics":{"type":"object","description":"Resource metrics keyed by pod name","additionalProperties":{"type":"object","properties":{"cpu_usage_percent":{"type":"number","description":"CPU usage as a percentage (0-100)"},"memory_usage_bytes":{"type":"number","description":"Memory usage in bytes"},"disk_read_bytes":{"type":"number","description":"Disk bytes read per second (with window) or cumulative (without window)"},"disk_read_operations":{"type":"number","description":"Disk read operations per second (with window) or cumulative count (without window)"},"disk_write_bytes":{"type":"number","description":"Disk bytes written per second (with window) or cumulative (without window)"},"disk_write_operations":{"type":"number","description":"Disk write operations per second (with window) or cumulative count (without window)"}}}}}}}}},"400":{"description":"Invalid app ID"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App or organization not found"},"422":{"description":"Organization is not fully configured"},"500":{"description":"Internal server error"},"503":{"description":"Metrics service unavailable"}},"tags":["Apps"]}},"/v1/apps/{appId}/deployments":{"get":{"summary":"List deployments","description":"Returns a list of deployments for the specified app, ordered by most recent first.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"},{"in":"query","name":"limit","schema":{"type":"integer","default":20},"description":"Maximum number of deployments to return"},{"in":"query","name":"status","schema":{"type":"string","enum":["queued","in_progress","succeeded","failed","created"]},"description":"Filter by deployment status"}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"type":"object","properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/Deployment"}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App not found"}},"tags":["Deployments"]},"post":{"summary":"Create a deployment","description":"Creates a new deployment for the specified app using its current spicepod configuration. The runtime image is selected based on the app's update channel.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"image_tag":{"type":"string","description":"Override the runtime image tag for this deployment"},"channel":{"type":"string","enum":["stable","preview","nightly","internal"],"description":"Update channel that determines the runtime image"},"replicas":{"type":"integer","minimum":1,"maximum":10,"description":"Override the number of replicas for this deployment"},"branch":{"type":"string","description":"Git branch name"},"commit_sha":{"type":"string","description":"Git commit SHA"},"commit_message":{"type":"string","description":"Git commit message"},"debug":{"type":"boolean","description":"Enable debug mode for this deployment"}}}}}},"responses":{"202":{"description":"Deployment created and queued for processing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deployment"}}}},"400":{"description":"Invalid request body or app has no spicepod configuration"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App not found"},"409":{"description":"A deployment is already in progress for this app"},"422":{"description":"Organization is not fully configured"},"500":{"description":"Internal server error"},"502":{"description":"Upstream service failure while provisioning the deployment"}},"tags":["Deployments"]}},"/v1/apps/{appId}/secrets":{"get":{"summary":"List secrets","description":"Returns all secrets for the specified app. Secret values are always masked.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"}],"responses":{"200":{"description":"List of secrets","content":{"application/json":{"schema":{"type":"object","properties":{"secrets":{"type":"array","items":{"$ref":"#/components/schemas/Secret"}}}}}}},"400":{"description":"Invalid app ID"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App not found"},"500":{"description":"Internal server error"}},"tags":["Secrets"]},"post":{"summary":"Create or update a secret","description":"Creates a new secret or updates an existing secret with the same name. The secret value is encrypted at rest.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string","pattern":"^[a-zA-Z_][a-zA-Z0-9_]*$","description":"Secret name (must start with a letter or underscore, alphanumeric and underscores only)"},"value":{"type":"string","description":"Secret value (will be encrypted at rest)"}}}}}},"responses":{"200":{"description":"Secret created or updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Secret"}}}},"400":{"description":"Invalid request body or app ID"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App not found"},"500":{"description":"Internal server error"}},"tags":["Secrets"]}},"/v1/apps/{appId}/secrets/{secretName}":{"get":{"summary":"Get a secret","description":"Returns a specific secret by name. The secret value is always masked.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"},{"in":"path","name":"secretName","required":true,"schema":{"type":"string"},"description":"The name of the secret"}],"responses":{"200":{"description":"Secret details (value is masked)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Secret"}}}},"400":{"description":"Invalid app ID"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App or secret not found"},"500":{"description":"Internal server error"}},"tags":["Secrets"]},"delete":{"summary":"Delete a secret","description":"Permanently deletes a secret by name.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"},{"in":"path","name":"secretName","required":true,"schema":{"type":"string"},"description":"The name of the secret"}],"responses":{"204":{"description":"Secret deleted successfully"},"400":{"description":"Invalid app ID"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App or secret not found"},"500":{"description":"Internal server error"}},"tags":["Secrets"]}},"/v1/apps/{appId}/api-keys":{"get":{"summary":"Get API keys","description":"Returns the API keys for a specific app. API keys are used to authenticate requests to the Spice.ai runtime.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"}],"responses":{"200":{"description":"API keys for the app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeys"}}}},"400":{"description":"Invalid app ID"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App not found"},"500":{"description":"Internal server error"}},"tags":["API Keys"]},"post":{"summary":"Regenerate an API key","description":"Regenerates an API key for the specified app. This invalidates the previous key. Use key_number to specify which key to regenerate (0 for both, 1 for primary, 2 for secondary).","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"appId","required":true,"schema":{"type":"integer"},"description":"The ID of the app"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"key_number":{"type":"integer","enum":[0,1,2],"default":1,"description":"Which API key to regenerate (0 = both, 1 = primary, 2 = secondary)"}}}}}},"responses":{"200":{"description":"API key regenerated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeysRegenerated"}}}},"400":{"description":"Invalid request body or app ID"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"App not found"},"500":{"description":"Internal server error"}},"tags":["API Keys"]}},"/v1/members":{"get":{"summary":"List organization members","description":"Returns all members of the authenticated organization.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"List of organization members","content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"integer"},"username":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"is_owner":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"}},"tags":["Members"]},"post":{"summary":"Add a member","description":"Adds a new member to the organization with the specified roles.","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["username"],"properties":{"username":{"type":"string","description":"The username of the user to add"},"roles":{"type":"array","items":{"type":"string"},"description":"Roles to assign to the new member","default":["member"]}}}}}},"responses":{"201":{"description":"Member added successfully","content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"integer"},"username":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"User not found"},"409":{"description":"User is already a member of this organization"}},"tags":["Members"]}},"/v1/members/{memberId}":{"get":{"summary":"Get a member","description":"Returns details for a specific organization member, including their roles.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"memberId","required":true,"schema":{"type":"integer"},"description":"The user ID of the member"}],"responses":{"200":{"description":"Member details","content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"integer"},"username":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"is_owner":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"Member not found"}},"tags":["Members"]},"patch":{"summary":"Update a member's roles","description":"Updates the roles assigned to a specific organization member. Organization owners cannot have their roles modified.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"memberId","required":true,"schema":{"type":"integer"},"description":"The user ID of the member"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["roles"],"properties":{"roles":{"type":"array","items":{"type":"string"},"description":"New roles to assign to the member"}}}}}},"responses":{"200":{"description":"Member roles updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"integer"},"username":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or cannot modify organization owner"},"404":{"description":"Member not found"}},"tags":["Members"]},"delete":{"summary":"Remove a member","description":"Removes a member from the organization. Organization owners cannot be removed.","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"memberId","required":true,"schema":{"type":"integer"},"description":"The user ID of the member"}],"responses":{"204":{"description":"Member removed successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or cannot remove organization owner"},"404":{"description":"Member not found"}},"tags":["Members"]}},"/v1/limits":{"get":{"summary":"Get organization limits","description":"Returns the current plan limits for the authenticated organization, including resource limits when private compute is enabled.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Organization limits","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"integer","description":"Maximum number of apps"},"replicas":{"type":"integer","description":"Maximum replicas per app"},"spicepods":{"type":"integer","description":"Maximum spicepods per app"},"users":{"type":"integer","description":"Maximum organization members (-1 means unlimited)"},"api_rps":{"type":"integer","description":"API requests per second limit"},"request_timeout_secs":{"type":"integer","description":"Request timeout in seconds"},"sql_query_timeout_secs":{"type":"integer","description":"SQL query timeout in seconds"},"sql_concurrent_queries":{"type":"integer","description":"Maximum concurrent SQL queries"},"resources":{"type":"object","nullable":true,"description":"Resource limits for private compute; `null` when private compute is not enabled","properties":{"max_cpu":{"type":"integer","description":"Maximum vCPUs per container"},"max_memory_gi":{"type":"integer","description":"Maximum memory in Gi per container"}}}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"Organization not found"}},"tags":["Limits"]}},"/v1/regions":{"get":{"summary":"List regions","description":"Returns the available regions where apps can be deployed.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"List of available regions","content":{"application/json":{"schema":{"type":"object","properties":{"regions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable region name"},"region":{"type":"string","description":"Region identifier (e.g., us-east-2)"},"provider":{"type":"string","enum":["teraswitch","aws","azure"]},"providerName":{"type":"string","enum":["Teraswitch","AWS","Azure"]},"isDefault":{"type":"boolean"},"disabled":{"type":"boolean"}}}},"default":{"type":"string","description":"The default region identifier"}}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"}},"tags":["Regions"]}},"/openapi.json":{"get":{"summary":"Get OpenAPI specification","description":"Returns the OpenAPI specification for the Spice Cloud Control-Plane API.","responses":{"200":{"description":"OpenAPI specification document","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["Documentation"]}}},"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth 2.0 access token obtained from the Spice.ai authentication service"}},"schemas":{"App":{"type":"object","properties":{"id":{"type":"integer","description":"Unique identifier for the app"},"name":{"type":"string","description":"Name of the app"},"description":{"type":"string","nullable":true,"description":"Description of the app"},"visibility":{"type":"string","enum":["public","private"],"description":"Visibility setting for the app"},"created_at":{"type":"string","format":"date-time","description":"Timestamp when the app was created"},"cname":{"type":"string","description":"Region identifier"},"cluster_id":{"type":"string","nullable":true,"description":"Cluster ID where the app is deployed"},"tags":{"type":"object","additionalProperties":{"type":"string"},"nullable":true,"description":"Key-value tags for the app"}}},"AppWithConfig":{"type":"object","properties":{"id":{"type":"integer","description":"Unique identifier for the app"},"name":{"type":"string","description":"Name of the app"},"description":{"type":"string","nullable":true,"description":"Description of the app"},"visibility":{"type":"string","enum":["public","private"],"description":"Visibility setting for the app"},"created_at":{"type":"string","format":"date-time","description":"Timestamp when the app was created"},"cname":{"type":"string","description":"Region identifier"},"production_branch":{"type":"string","nullable":true,"description":"Production branch for the app"},"api_key":{"type":"string","deprecated":true,"description":"Deprecated. Use the API Keys endpoints instead."},"tags":{"type":"object","additionalProperties":{"type":"string"},"nullable":true,"description":"Key-value tags for the app"},"warning":{"type":"string","nullable":true,"description":"Present when the app was created but initial configuration could not be applied"},"config":{"type":"object","properties":{"spicepod":{"type":"object","nullable":true,"description":"Spicepod configuration"},"registry":{"type":"string","nullable":true,"description":"Container registry for the runtime image"},"image_tag":{"type":"string","nullable":true,"description":"Runtime image tag"},"update_channel":{"type":"string","enum":["stable","preview","nightly","internal"],"nullable":true,"description":"Update channel for the runtime"},"replicas":{"type":"integer","description":"Number of replicas"},"resources":{"type":"object","nullable":true,"description":"Resource requests and limits for the app container","properties":{"limits":{"type":"object","properties":{"cpu":{"type":"string","description":"Whole-number vCPU limit, or '-' for no CPU limit"},"memory":{"type":"string","description":"Memory limit in Gi (for example, 16Gi)"},"ephemeral-storage":{"type":"string"}}},"requests":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"}}}}},"executor":{"type":"object","nullable":true,"description":"Executor container configuration","properties":{"replicas":{"type":"integer","description":"Number of executor replicas"},"resources":{"type":"object","description":"Resource requests and limits for the executor container","properties":{"limits":{"type":"object","properties":{"cpu":{"type":"string","description":"Whole-number vCPU limit, or '-' for no CPU limit"},"memory":{"type":"string","description":"Memory limit in Gi (for example, 16Gi)"},"ephemeral-storage":{"type":"string"}}},"requests":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"}}}}}}},"region":{"type":"string","nullable":true,"description":"Cloud region code (e.g., us-east-1)"},"node_group":{"type":"string","nullable":true,"description":"Node group for scheduling the app runtime"},"storage_claim_size_gb":{"type":"number","nullable":true,"description":"Storage claim size in GB"}}}}},"Secret":{"type":"object","properties":{"id":{"type":"integer","description":"Unique identifier for the secret"},"name":{"type":"string","description":"Name of the secret"},"value":{"type":"string","description":"Always masked with asterisks"},"created_at":{"type":"string","format":"date-time","description":"Timestamp when the secret was created"},"updated_at":{"type":"string","format":"date-time","description":"Timestamp when the secret was last updated"}}},"Deployment":{"type":"object","properties":{"id":{"type":"integer","description":"Unique identifier for the deployment"},"status":{"type":"string","enum":["queued","in_progress","succeeded","failed","created"],"description":"Current status of the deployment"},"created_at":{"type":"string","format":"date-time","description":"Timestamp when the deployment was created"},"started_at":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp when the deployment started"},"updated_at":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp when the deployment was last updated"},"image_tag":{"type":"string","nullable":true,"description":"Runtime image tag used for this deployment"},"replicas":{"type":"integer","description":"Number of replicas"},"branch":{"type":"string","nullable":true,"description":"Git branch name"},"commit_sha":{"type":"string","nullable":true,"description":"Git commit SHA"},"commit_message":{"type":"string","nullable":true,"description":"Git commit message"},"error_message":{"type":"string","nullable":true,"description":"Error message if the deployment failed"},"creation_source":{"type":"string","nullable":true,"description":"Source that triggered the deployment"},"created_by":{"type":"string","nullable":true,"description":"User who created the deployment"}}},"ApiKeys":{"type":"object","properties":{"api_key":{"type":"string","nullable":true,"description":"Primary API key"},"api_key_2":{"type":"string","nullable":true,"description":"Secondary API key (for key rotation)"}}},"ApiKeysRegenerated":{"type":"object","properties":{"api_key":{"type":"string","nullable":true,"description":"Primary API key"},"api_key_2":{"type":"string","nullable":true,"description":"Secondary API key"},"regenerated_key":{"type":"integer","enum":[0,1,2],"description":"Which key was regenerated (0 = both, 1 = primary, 2 = secondary)"}}}}},"tags":[{"name":"Health","description":"API health and status"},{"name":"Apps","description":"Manage apps and their configurations"},{"name":"Deployments","description":"Create and monitor app deployments"},{"name":"Secrets","description":"Manage encrypted app secrets"},{"name":"API Keys","description":"Manage runtime API keys for apps"},{"name":"Members","description":"Manage organization members and roles"},{"name":"Regions","description":"Available deployment regions"},{"name":"Limits","description":"Organization plan limits"},{"name":"Documentation","description":"API specification and documentation"}]}