openapi: 3.0.3 info: title: Volcano Hosting API description: |- Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. version: 3.0.0 contact: name: Volcano Hosting email: support@volcano.dev servers: - url: https://api.volcano.dev description: Production API server - url: http://localhost:8000 description: Development API server (use VOLCANO_API_URL env var) tags: - name: Projects description: Project management operations - name: Logs description: Project-scoped log search and activity APIs - name: Functions description: Function deployment and management - name: Durable Functions description: |- Long-running functions that checkpoint their progress and resume from the last completed step, and the executions started against them. Separate from Functions because a durable function is started asynchronously: what a start returns is an execution to poll and stop, not a result. Durable work is metered on its own allowances: executions, and the operations each execution performs while it runs. - name: Frontends description: Frontend deployment and management. Supports Next.js 15.x and 16.x with Node.js 22.x or 24.x inferred from package.json engines.node when the selected Node.js family satisfies the installed Next.js package engines.node constraint. - name: Tokens description: Service keys for function invocation and database admin access - name: Variables description: Environment variable management - name: Databases description: Serverless PostgreSQL database provisioning and management - name: Database Branches description: Short-lived forks of a database for development and testing - name: Database Queries description: REST API for querying databases (SELECT, INSERT, UPDATE, DELETE) - name: Authentication description: End-user authentication (signup, signin, profile) - name: Auth Admin description: Auth user management (platform admin only) - name: Auth Configuration description: Authentication settings and anon keys - name: Anon Keys description: Project-specific public keys for frontend auth - name: Service Keys description: Project-specific secret keys for admin operations (bypass RLS - backend only!) - name: OAuth Configuration description: OAuth provider configuration (Google, GitHub, Microsoft, Apple) - name: OAuth Authentication description: OAuth login flows and provider management for end users - name: Git Connections description: Platform-user git provider connections for deployment source integrations - name: Project Imports description: Read-only project source discovery and import readiness checks - name: Storage Buckets description: Storage bucket management (platform admin) - name: Storage Policies description: Storage access policy management (platform admin) - name: Storage Admin description: Storage statistics and cross-bucket object listing (platform admin) - name: Storage Objects description: File upload, download, and management (SDK-facing) - name: Locks description: Project-scoped leases for backend coordination (service-role keys only) - name: Realtime description: WebSocket realtime configuration and monitoring - name: System description: System health and monitoring endpoints - name: CLI Authentication description: | Browser-based CLI login flow for automatic token provisioning. The CLI creates a session, opens a browser for user authentication, and polls for completion. Session completion is handled by volcano.dev via the Management API. paths: /user/imports/connect: post: tags: - Project Imports summary: Start a project import provider connection description: | Starts a first-party dashboard user's provider connection flow. The response sets a short-lived HttpOnly browser-binding cookie for the public provider callback. operationId: startImportConnect security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: provider in: query required: false description: Import provider to connect. Defaults to Vercel. schema: $ref: '#/components/schemas/ImportProvider' - name: redirect in: query required: false description: Validated application URL used after the provider callback. schema: type: string format: uri pattern: ^https://[^/?#]+(?:[/?][^#]*)?$|^http://(?:localhost|127\.0\.0\.1|\[::1\])(?::[0-9]+)?(?:[/?][^#]*)?$ responses: '200': description: Provider authorization URL content: application/json: schema: $ref: '#/components/schemas/ImportConnectStartResponse' '400': description: Unsupported provider or invalid redirect content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to start the connection content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Import provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /imports/{provider}/callback: get: tags: - Project Imports summary: Complete a project import provider connection description: | Public provider callback protected by signed state and the browser-binding cookie created by startImportConnect. operationId: completeImportConnect security: [] parameters: - name: provider in: path required: true schema: $ref: '#/components/schemas/ImportProvider' - name: state in: query required: true description: Signed connect state generated by startImportConnect. schema: type: string - name: code in: query required: false description: Provider authorization code. schema: type: string - name: error in: query required: false description: Provider error category. schema: type: string - name: teamId in: query required: false description: Vercel team selected during installation. schema: type: string - name: configurationId in: query required: false description: Vercel Integration configuration identifier. schema: type: string - name: next in: query required: false description: Provider completion URL validated by the provider adapter. schema: type: string - name: source in: query required: false description: Vercel installation source indicator. schema: type: string responses: '303': description: Redirect to the provider completion URL, signed application redirect, or Volcano import page headers: Location: description: Validated redirect target schema: type: string '400': description: Invalid callback request, state, or browser binding content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Too many callback attempts content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to complete the connection content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Import provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /user/imports/connections: get: tags: - Project Imports summary: List project import provider connections operationId: listImportConnections security: - UserToken: [] - AuthUserAccessToken: [] responses: '200': description: Stored import provider connections content: application/json: schema: $ref: '#/components/schemas/ImportConnectionsResponse' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to list connections content: application/json: schema: $ref: '#/components/schemas/Error' /user/imports/connections/{connectionId}: delete: tags: - Project Imports summary: Delete a project import provider connection operationId: deleteImportConnection security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: connectionId in: path required: true description: Connection ID to delete. schema: type: string format: uuid responses: '204': description: Connection deleted '400': description: Malformed connection ID content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Connection not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Connection changed while it was being deleted content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to delete the connection content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Import provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /imports/{provider}/sources: get: tags: - Project Imports summary: List project sources available from a provider connection description: Lists provider projects without changing provider or Volcano resources. operationId: listImportSources security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: provider in: path required: true schema: $ref: '#/components/schemas/ImportProvider' - name: connection_id in: query required: true description: Owned provider connection used for discovery. schema: type: string format: uuid responses: '200': description: Provider sources available to import content: application/json: schema: $ref: '#/components/schemas/ImportSourcesResponse' '400': description: Invalid provider or connection ID content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: The provider connection lacks a required Integration scope content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Connection or provider source not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: The provider connection must be reconnected content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Provider rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to list provider sources content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Provider unavailable or integration not configured content: application/json: schema: $ref: '#/components/schemas/Error' /imports/{provider}/preflight: post: tags: - Project Imports summary: Check whether a provider project is ready to import description: Produces a deterministic read-only readiness report for a proposed new Volcano project. operationId: preflightProjectImport security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: provider in: path required: true schema: $ref: '#/components/schemas/ImportProvider' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ProjectImportPreflightRequest' responses: '200': description: Import readiness report content: application/json: schema: $ref: '#/components/schemas/ProjectImportReport' '400': description: Invalid provider, source, project name, or target content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: The provider connection lacks a required Integration scope content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Connection or provider source not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: The provider connection must be reconnected content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Provider rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to produce an import readiness report content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Provider unavailable or integration not configured content: application/json: schema: $ref: '#/components/schemas/Error' /imports/{provider}/runs: post: tags: - Project Imports summary: Start a Vercel project import description: Creates a Volcano project from an importable production preflight report. Retrying the same request with the same Idempotency-Key returns the existing run. operationId: startProjectImport security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: provider in: path required: true schema: $ref: '#/components/schemas/ImportProvider' - name: Idempotency-Key in: header required: true schema: type: string minLength: 1 maxLength: 255 pattern: ^[!-~]+$ requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ProjectImportStartRequest' responses: '202': description: Import run accepted headers: Location: required: true schema: type: string content: application/json: schema: $ref: '#/components/schemas/ProjectImportRun' '400': description: Invalid request or idempotency key content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Provider permission or project admission denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Connection or provider source not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Preflight is stale, idempotency key was reused, or destination conflicts content: application/json: schema: $ref: '#/components/schemas/Error' '422': description: Source is not importable content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Provider rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to start the import content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Provider unavailable or integration not configured content: application/json: schema: $ref: '#/components/schemas/Error' /imports/{provider}/runs/{runId}: get: tags: - Project Imports summary: Get a project import run operationId: getProjectImportRun security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: provider in: path required: true schema: $ref: '#/components/schemas/ImportProvider' - name: runId in: path required: true schema: type: string format: uuid responses: '200': description: Import run status content: application/json: schema: $ref: '#/components/schemas/ProjectImportRun' '400': description: Invalid import run ID content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Import run not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to get the import run content: application/json: schema: $ref: '#/components/schemas/Error' /user/git/connect: post: tags: - Git Connections summary: Start a git provider connection description: | Starts a first-party dashboard user's git provider connection flow and returns the provider authorization URL. The response also sets a short-lived HttpOnly callback binding cookie tied to the authenticated user through the signed provider state. operationId: startGitConnect security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: provider in: query required: false description: Git provider to connect. Defaults to github. schema: type: string enum: - github default: github - name: redirect in: query required: false description: URL to redirect the browser to after the provider callback completes. schema: type: string responses: '200': description: Provider authorization URL content: application/json: schema: $ref: '#/components/schemas/GitConnectStartResponse' '400': description: Unsupported provider or invalid redirect content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to start the connection content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Git provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /user/git/connections: get: tags: - Git Connections summary: List git provider connections operationId: listGitConnections security: - UserToken: [] - AuthUserAccessToken: [] responses: '200': description: Stored git provider connections content: application/json: schema: $ref: '#/components/schemas/GitConnectionsResponse' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to list connections content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Git provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /user/git/connections/{connectionId}: delete: tags: - Git Connections summary: Delete a git provider connection operationId: deleteGitConnection security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: connectionId in: path required: true description: Connection ID to delete schema: type: string format: uuid responses: '204': description: Connection deleted '400': description: Malformed connection ID content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Connection not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to delete connection content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Git provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /user/git/connections/{connectionId}/installations: get: tags: - Git Connections summary: List GitHub App installations accessible to a connection description: | Live proxy to GitHub: lists the platform GitHub App installations the connection's stored user token can access. Nothing is persisted by this call. operationId: listGitInstallations security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: connectionId in: path required: true description: Connection ID to browse installations for. schema: type: string format: uuid responses: '200': description: Installations accessible to the connection content: application/json: schema: $ref: '#/components/schemas/GitInstallationsResponse' '400': description: Malformed connection ID content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Connection not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to list installations content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Git provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /user/git/connections/{connectionId}/installations/{installationId}/repositories: get: tags: - Git Connections summary: List repos accessible to a connection through an installation description: | Live proxy to GitHub: lists the repos the connection's stored user token can access through installationId. Nothing is persisted by this call. operationId: listGitInstallationRepositories security: - UserToken: [] - AuthUserAccessToken: [] parameters: - name: connectionId in: path required: true description: Connection ID to browse repositories for. schema: type: string format: uuid - name: installationId in: path required: true description: GitHub App installation ID. schema: type: integer format: int64 responses: '200': description: Repositories accessible through the installation content: application/json: schema: $ref: '#/components/schemas/GitRepositoriesResponse' '400': description: Malformed connection or installation ID content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Connection not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to list repositories content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Git provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /github/callback: get: tags: - Git Connections summary: Complete a GitHub App connection callback description: | Public GitHub App callback. The signed state and callback binding cookie bind the provider authorization to the browser that started the flow. operationId: gitConnectCallback security: [] parameters: - name: code in: query required: false description: GitHub user authorization code. schema: type: string - name: state in: query required: true description: Signed connect state generated by startGitConnect. schema: type: string - name: error in: query required: false description: Provider error returned by GitHub. schema: type: string responses: '303': description: Redirect back to the app after a successful or failed connect attempt headers: Location: description: Redirect target schema: type: string '400': description: Invalid callback request or state content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Too many callback attempts from this client content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to complete the connection content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Git provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /projects: get: tags: - Projects summary: List all projects for authenticated user description: | Returns projects that are not deleting or deleted, newest first. Supports two mutually exclusive pagination modes. Offset mode uses `page` and `limit`. Cursor mode uses `cursor` or `ending_before` with `limit`, returns `next_cursor`/`prev_cursor`, and supports a bounded `offset` past the cursor anchor. Supplying `limit` without `page` selects cursor mode. `search` applies a case-insensitive project-name filter in either mode. `include` optionally expands each returned project with its Git connection and/or aggregate health summary using `git_connection` and `health`. Sending `page` with `cursor` or `ending_before`, or sending both cursor directions, returns 400. operationId: listProjects security: - UserToken: [] parameters: - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' - name: include in: query required: false description: Optional comma-separated project metadata expansions. style: form explode: false schema: type: array uniqueItems: true items: type: string enum: - git_connection - health responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedProjects' '400': description: Invalid or conflicting pagination parameters content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Projects summary: Create a new project description: | Creates a project for the authenticated user. Each user can create up to 1,000 projects. Requests over this cap return 403. operationId: createProject security: - UserToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateProjectRequest' responses: '201': description: Project created content: application/json: schema: $ref: '#/components/schemas/Project' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Project limit exceeded for the user content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}: get: tags: - Projects summary: Get project by ID operationId: getProject security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/Project' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' patch: tags: - Projects summary: Update project metadata and region policy operationId: updateProject security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateProjectRequest' responses: '200': description: Project updated content: application/json: schema: $ref: '#/components/schemas/Project' '400': description: | Bad request (no region selected, an unknown region, or — for a project holding durable functions — a region that does not offer durable execution) content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden (for example, selecting subset regions on non-SUPERAGENT plan) content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Conflict (project name already exists or a resource deployment blocks a region change) content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Projects summary: Delete a project description: | Starts asynchronous project deletion. The project remains available from `GET /projects/{id}` with `status: deleting` until cleanup finishes, but is removed from project lists as soon as deletion starts. After cleanup it returns 404. operationId: deleteProject security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '202': description: Project deletion started '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/health: get: tags: - Projects summary: Get project health description: | Returns a fast control-plane health snapshot for the project and its deployed resources. The endpoint does not run live provider probes. A successful request returns 200 even when the project status is `unhealthy`; transport and authorization failures use HTTP errors. operationId: getProjectHealth security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Project health snapshot retrieved content: application/json: schema: $ref: '#/components/schemas/ProjectHealthResponse' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/metrics/query: post: tags: - Projects summary: Query project runtime metrics description: | Evaluates a batch of named, curated runtime metric queries over one trailing time range. Query IDs correlate each request with its result; raw backend query languages are intentionally not exposed. operationId: queryProjectMetrics security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ProjectMetricsQueryRequest' responses: '200': description: Project runtime metric queries evaluated content: application/json: schema: $ref: '#/components/schemas/ProjectMetricsQueryResponse' '400': description: Invalid metric query content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Runtime metrics backend unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/logo: get: tags: - Projects summary: Get the project logo image description: | Returns the raw logo image stored in the project's storage folder. This endpoint is unauthenticated so the asset can be rendered directly in an `` tag; project IDs are unguessable UUIDs and logos are non-sensitive branding. The `Project.logo_url` field exposes a versioned path to this endpoint. operationId: getProjectLogo security: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Logo image content: image/png: schema: type: string format: binary image/jpeg: schema: type: string format: binary image/gif: schema: type: string format: binary image/webp: schema: type: string format: binary image/svg+xml: schema: type: string format: binary '404': description: Project or logo not found content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Projects summary: Upload or replace the project logo description: | Uploads an image as the project's logo, storing it in the project's storage folder. Accepts PNG, JPEG, GIF, WebP, or SVG up to 2 MB. Replaces any existing logo. Returns the updated project, whose `logo_url` reflects the new logo. operationId: uploadProjectLogo security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: multipart/form-data: schema: type: object required: - logo properties: logo: type: string format: binary description: Logo image (PNG, JPEG, GIF, WebP, or SVG; max 2 MB) responses: '200': description: Logo uploaded content: application/json: schema: $ref: '#/components/schemas/Project' '400': description: Bad request (missing file, unsupported type, or too large) content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Project is being deleted content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Logo storage is not configured content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Projects summary: Remove the project logo description: | Deletes the project logo from the project's storage folder and clears its record. Returns the updated project with no `logo_url`. operationId: deleteProjectLogo security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Logo removed content: application/json: schema: $ref: '#/components/schemas/Project' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Project is being deleted content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Logo storage is not configured content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/usage: get: tags: - Projects summary: Get usage metrics for a project description: | Returns project usage totals for the current usage month plus recent hourly and daily time series for each tracked metric. operationId: getProjectUsage security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Usage metrics retrieved content: application/json: schema: $ref: '#/components/schemas/ProjectUsageResponse' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/shared-variables: put: tags: - Projects summary: Replace shared variable names description: | Atomically replaces the complete shared function-variable list without changing values. Names must already exist. Validates final affected function environments before membership or propagation side effects. An empty list clears membership. Omitted names remain stored as non-shared variables. operationId: replaceSharedVariables security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - shared_variables not: required: - expected_shared_variables - expected_shared_variables_digest properties: shared_variables: type: array uniqueItems: true items: type: string maxLength: 256 pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ expected_shared_variables: type: array uniqueItems: true description: When present, replace only if the current complete shared list matches this list. items: type: string maxLength: 256 pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ expected_shared_variables_digest: type: string minLength: 64 maxLength: 64 pattern: ^[a-f0-9]{64}$ description: SHA-256 of the sorted unique current shared names joined by a newline. Use instead of expected_shared_variables for a compact conditional replacement. responses: '204': description: Shared list replaced and affected function synchronization started. '400': description: Invalid names or final function environment. content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized '404': description: Project not found '409': description: Shared list changed since it was read. content: application/json: schema: $ref: '#/components/schemas/Error' '413': description: Request body exceeds 4,194,304 bytes content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Persistence or synchronization failed '503': description: Shared variable membership writes are disabled during rollout content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/config: get: tags: - Projects summary: Export project configuration description: | Exports the project's current user-facing configuration as a declarative manifest. Returns JSON by default. Request the canonical volcano-config.yaml rendering with `Accept: application/yaml` or `?format=yaml`; the YAML is returned verbatim as the raw response body (`Content-Type: application/yaml`) and is meant to be saved as-is. Variable values and write-only secrets (SMTP password, OAuth client secrets, TLS material) are omitted from the export; shared_variables contains names only; the YAML rendering adds a header comment describing how to set them via CLI environment interpolation. operationId: getProjectConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: format in: query required: false description: Response format override. Takes precedence over the Accept header. schema: type: string enum: - json - yaml responses: '200': description: | Current project configuration. JSON by default; when YAML is requested the body is the canonical volcano-config.yaml document served verbatim with `Content-Type: application/yaml`. content: application/json: schema: $ref: '#/components/schemas/ProjectConfig' application/yaml: schema: type: string format: binary description: | Canonical volcano-config.yaml document returned verbatim, ready to be saved as-is. The response body is limited to 4,194,304 bytes, matching the configuration apply limit. '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '413': description: Canonical YAML export exceeds 4,194,304 bytes content: application/json: schema: $ref: '#/components/schemas/Error' put: tags: - Projects summary: Apply project configuration description: | Validates and applies a declarative configuration manifest to the project, reconciling each declared section and returning a per-resource report. Omitted sections are untouched. Declared collection keys (`variables`, `buckets[].policies`, `auth.providers.oauth`, `auth.email.templates`, `functions[].schedulers`) are fully synced: resources absent from the manifest are deleted. Functions, frontends, databases, and buckets are never created or deleted; manifest entries for resources that do not exist are skipped and reported in `skipped`, and existing resources missing from a declared section are reported in `missing`. Validation failures (including plan-gate violations) return 422 and nothing is applied. Set `dry_run=true` to get the projected report without applying changes. Applies are serialized per project; a concurrent apply returns 409. operationId: applyProjectConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: dry_run in: query required: false description: Validate and report projected actions without applying changes. schema: type: boolean default: false requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ProjectConfig' responses: '200': description: | Apply report. Individual entries may still carry `action: error` for apply-phase failures (summary.errors > 0); already-applied changes are not rolled back. content: application/json: schema: $ref: '#/components/schemas/ProjectConfigApplyResult' '400': description: Malformed request body content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Another apply is in progress for this project content: application/json: schema: $ref: '#/components/schemas/Error' '422': description: Manifest validation failed; nothing was applied content: application/json: schema: $ref: '#/components/schemas/ProjectConfigValidationErrorResponse' '503': description: Shared variable membership writes are disabled during rollout content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/source-export: get: tags: - Projects - Git Connections summary: Report the project's source-of-truth state operationId: getProjectSourceExport description: | Volcano stores the source of the functions and frontend it runs for a project. This reports whether that source has been written to the connected repository, and whether the repository has taken over as the project's source of truth. `mode` is `platform`, `git_exporting`, `git_pending`, or `git`. Export enters `git_exporting` before reading stored source. GitHub's signed push event confirms that the initial commit reached the production branch. That push or a newer production push changes the mode to `git_pending` when it starts a deployment. `exported_at` records that transition. A successful Git run completes the transition when it matches the recorded repository, production branch, and root directory and actually dispatches every recorded resource. Ordinary production-branch pushes deploy without changing a platform-managed project's source ownership. security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: The project's source-of-truth state content: application/json: schema: $ref: '#/components/schemas/ProjectSourceExportState' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project not owned by the caller content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' '501': description: Source export is not available in this deployment mode content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Projects - Git Connections summary: Initialize an empty repository with a project's stored source operationId: exportProjectSource description: | Creates the first commit in the connected repository and pushes it directly to the configured production branch. The push enters the ordinary Git auto-deploy flow. Direct source writes remain frozen until that deployment succeeds and the repository becomes the source of truth. The caller confirms the production branch shown before export. Starting export pins that branch: later GitHub default-branch changes do not repoint the project. If the configured branch changed after the caller read it, the request fails without exporting so the caller can show and confirm the new value. The response lists what the export could not carry: resources with no successful deployment to take source from (`skipped`), and things no export can hand back (`omitted`) — migrations, which Volcano stores no copy of, and credential-shaped files, which are left for their owner to add. Requires a connected repository with no commits or branches, and runs once. Volcano never creates the repository. If GitHub did not confirm the push, retrying creates the same commit and adopts it when it already reached the repository. security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ExportProjectSourceRequest' responses: '201': description: The initial production-branch commit that was pushed content: application/json: schema: $ref: '#/components/schemas/ProjectSourceExport' '400': description: Malformed request body content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project not owned by the caller content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found, or it has no repository connected content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | The source has already been exported, the repository has already taken over as the source of truth, the confirmed production branch is stale, a function or frontend deployment is still in progress, or the project has no stored source to export content: application/json: schema: $ref: '#/components/schemas/Error' '422': description: | The repository refused the branch, or its contents cannot be laid out as a repository — a stored file that only ever carries credentials, or a layout Git auto-deploy would not read back content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: GitHub rate limited the request content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' '501': description: Source export is not available in this deployment mode content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: GitHub integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Projects - Git Connections summary: Cancel an incomplete source export operationId: cancelProjectSourceExport description: | Restores platform source writes while the project is in `git_exporting` or `git_pending`. If Volcano reserved or deployed the root commit, export remains consumed and cannot be run again. The connected repository and any commit already pushed to it are unchanged. security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '204': description: The incomplete source transition was canceled '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project not owned by the caller content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: No incomplete transition exists, or Git already took ownership content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' '501': description: Source export is not available in this deployment mode content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/git-connection/production-branch: put: tags: - Projects - Git Connections summary: Set the branch a project deploys from description: | Changes only the production branch, leaving the repository binding alone. PUT /projects/{id}/git-connection can also set it, but that is a full rebind: it needs connection_id, installation_id and a repository selector resent, and re-resolves the repository against GitHub for a field that does not depend on it. The branch does not have to exist. It is validated as a Git branch name and nothing more, so a project can be pointed at a branch that is about to be pushed — the case a repository created empty depends on. Setting the branch here marks it as the project's own choice, so a later default-branch rename on GitHub no longer moves it. Projects that never set one keep following the repository's default branch. operationId: setProjectGitProductionBranch security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SetProjectGitProductionBranchRequest' responses: '200': description: The project's repo connection, with the new branch content: application/json: schema: $ref: '#/components/schemas/ProjectGitConnection' '400': description: | Malformed request body, or a production_branch that is not a valid Git branch name content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Project not owned by the caller content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: | Project not found, or it has no repository connected. The branch is part of the connection, so there is nothing to set it on until one exists. content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: A Git source transition is pending content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to set the production branch content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/git-connection: get: tags: - Projects - Git Connections summary: Get a project's repo connection operationId: getProjectGitConnection security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: The project's current repo connection content: application/json: schema: $ref: '#/components/schemas/ProjectGitConnection' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Project not owned by the caller content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found, or has no repo connection content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to get project git connection content: application/json: schema: $ref: '#/components/schemas/Error' put: tags: - Projects - Git Connections summary: Connect or update a project's repo connection description: | Full replace, following Vercel's model: many projects may point at the same repo, so this only binds the project — it never creates or deletes git-provider state. Used for both the initial connect and later edits (repo change, root directory, production branch). Resolves the repository_id or repo_full_name selector against the repos accessible through installation_id via connection_id's stored GitHub user token, then persists repository metadata only from that validated GitHub response. operationId: connectProjectGit security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ConnectProjectGitRequest' responses: '200': description: The project's repo connection content: application/json: schema: $ref: '#/components/schemas/ProjectGitConnection' '400': description: | Malformed request body, no repository selector, selectors that identify different repositories, a production_branch that is not a valid Git branch name, no production_branch on a repository with no default branch to follow (name one to connect a repository that has no commits yet), or a production_branch other than the new repository's default in a request that also changes repository. content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | Project not owned by the caller, or the selected repository is not accessible through installation_id content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or connection not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | A Git source transition is pending or complete, so the recorded repository and root cannot be changed content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to connect project git content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Git provider integration is not configured content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Projects - Git Connections summary: Disconnect a project's repo connection operationId: disconnectProjectGit security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '204': description: Connection removed '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Project not owned by the caller content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found, or has no repo connection content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | A Git source transition is pending or complete, so the recorded repository cannot be disconnected content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to disconnect project git content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/git-deploy-settings: get: tags: - Projects - Git Connections summary: Get a project's Git auto-deploy settings operationId: getProjectGitDeploySettings security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: The project's current Git auto-deploy settings content: application/json: schema: $ref: '#/components/schemas/ProjectGitDeploySettings' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Project not owned by the caller content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to get project git deploy settings content: application/json: schema: $ref: '#/components/schemas/Error' put: tags: - Projects - Git Connections summary: Update a project's Git auto-deploy settings description: | Full replace of the project's Git auto-deploy settings: what a push to the connected repo's production branch deploys. Connecting a repository sets auto_deploy_enabled and deploy_functions to true for a project that has never called this endpoint, so a push deploys without any further setup. Once these settings have been saved here they are the project's own: connecting, rebinding, disconnecting and reconnecting all leave them untouched, including when they were saved before any repository was connected. Frontend settings are off until set here; the frontend need not exist when they are saved, since frontend_name is resolved at deploy time. operationId: updateProjectGitDeploySettings security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateProjectGitDeploySettingsRequest' responses: '200': description: The project's updated Git auto-deploy settings content: application/json: schema: $ref: '#/components/schemas/ProjectGitDeploySettings' '400': description: Malformed request body, or frontend_app_root without frontend_name content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Project not owned by the caller content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | A Git source transition is pending, or this change would remove deploy coverage after Git has taken over content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to update project git deploy settings content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/queries: get: tags: - Databases summary: Get database queries description: | Returns the database's current top queries from pg_stat_statements ranked by total execution time. **SUPERAGENT plan required.** This endpoint is only available to projects owned by users on the SUPERAGENT billing plan. operationId: getProjectDatabaseQueries security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - name: limit in: query description: Maximum number of queries to return. schema: type: integer minimum: 1 maximum: 100 default: 10 responses: '200': description: Database query performance retrieved content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryPerformanceResponse' '400': description: Bad request - invalid query parameters content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or database not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /deployments: get: tags: - Projects summary: List deployments across a user's projects description: | Lists Function and Frontend deployment attempts across every project the user owns, newest first. Pass `project_id` to narrow the feed to a single project. Scope is project **ownership** (`projects.user_id`). `owner_id` names whose deployments to return, not who started them — the actor is `initiated_by_user_id`, which this endpoint does not filter on. With a user token the scope is always the authenticated user: `owner_id` may be omitted, or set to that same user, but naming anyone else is refused with 403. Service callers on the management API must pass it, since they have no authenticated user. The owner is not checked for existence: an id with no projects returns an empty page rather than `404`. Unlike `/users/{id}/usage`, this endpoint is polled to detect an event, so a caller needs `404` to keep meaning "this route is not served here" — which is how a consumer notices it is running against an older release. A mistyped owner therefore reads as "nothing deployed"; callers that need to tell those apart should verify the user through `GET /users/{id}` first. Ordering is selectable. The default is the feed order — most recent attempt first. `completed_at.asc` orders by completion, oldest first, and considers only attempts that finished; combined with `limit=1` and a `status` filter it answers "when did this user first succeed" in one bounded query. Both pagination modes are supported, selected exactly as `/projects/{id}/deployments` selects them: `cursor`/`ending_before` (or a `limit` with no `page`) uses keyset pagination; otherwise `page`/`limit` offset pagination. `page` with a cursor, and `cursor` with `ending_before`, are rejected. A cursor is bound to every filter *and* to `order`, so changing any of them mid-pagination rejects the cursor rather than silently skipping or repeating rows. The keyset position is `(created_at, id)` for `created_at.desc` and `(completed_at, id)` for `completed_at.asc`. operationId: listDeployments security: - UserToken: [] parameters: - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/DeploymentOwnerId' - name: project_id in: query required: false description: Restrict the feed to a single project owned by the user. schema: type: string format: uuid - name: created_after in: query required: false description: Restrict results to attempts created at or after this timestamp. schema: type: string format: date-time - $ref: '#/components/parameters/DeploymentResourceType' - $ref: '#/components/parameters/DeploymentStatus' - $ref: '#/components/parameters/DeploymentOperation' - $ref: '#/components/parameters/DeploymentOrder' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedProjectDeployments' '400': description: Bad request - invalid filter or pagination content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - owner_id names a different user content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/deployments: get: tags: - Projects summary: List deployments in a project description: | Lists Function and Frontend deployment attempts across the project, ordered most-recent first. Each item includes a normalized resource reference so clients can render both resource types without extra fetches. operationId: listProjectDeployments security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' - name: created_after in: query required: false description: Restrict results to attempts created at or after this timestamp. schema: type: string format: date-time - name: resource_type in: query required: false description: | Restrict the feed to a single resource type. Omit to return both Function and Frontend deployments. schema: type: string enum: - function - frontend responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedProjectDeployments' '400': description: Bad request - invalid identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/deployments/summary: get: tags: - Projects summary: Summarize deployments in a project description: | Summarizes deployment attempts for one comparable resource pipeline. Success rate uses conclusive outcomes only: active and deleted attempts are successful; failed and degraded attempts are failures; in-progress and superseded attempts are excluded. Median build duration includes completed, non-superseded attempts with recorded build work, including failed builds. operationId: summarizeProjectDeployments security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: search in: query required: false description: Restrict the summary to resource names containing this value. schema: type: string - name: resource_type in: query required: true description: Restrict the summary to one comparable deployment pipeline. schema: type: string enum: - function - frontend - name: created_after in: query required: false description: Restrict results to attempts created at or after this timestamp. schema: type: string format: date-time responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/ProjectDeploymentSummary' '400': description: Bad request - invalid identifier or filter content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/domains: get: tags: - Frontends summary: List all custom domains in a project description: | Project-scoped custom-domain list. Returns every active custom domain across every frontend in the project (excludes soft-deleted rows). Each item inlines the linked frontend's id and name so the UI does not need a second fetch to render the "Linked to" column. operationId: listProjectCustomDomains security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedProjectCustomDomains' '400': description: Bad request - invalid identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/functions: get: tags: - Functions summary: List all functions in a project description: | Supports two mutually exclusive pagination modes. Offset mode uses `page` and `limit` and returns `next` (URL). Cursor mode uses `cursor` and `limit`, supports `search` (case-insensitive name match), and returns `next_cursor`/`prev_cursor`. Sending both `page` and `cursor` (or `page` and `search`) returns 400. operationId: listFunctions security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedFunctions' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Functions summary: Create or update function code description: | Upload a serverless function source bundle. Direct API clients may send the function code as a ZIP or tar.gz archive via multipart/form-data. The API stores a normalized tar.gz source archive. Cloud deploys should include source files and dependency manifests/lockfiles, not installed dependency directories. Volcano installs Node.js, Python, and Ruby dependencies during the function compile build. Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI does not apply its own source archive size limit. After the final container image is built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing. Uploaded source archives cannot contain symlink entries. Safe symlinks created during the cloud build are materialized before publish. Volcano builds and deploys the function asynchronously after upload. A deployment that starts immediately returns a Function resource with `status: provisioning`, then transitions to `active` or `failed`. If another deployment is running, the response preserves the resource's current status and exposes the queued deployment through `pending_deployment_id`. Existing function traffic continues to use the last known-good runtime during an update. A failed update keeps that runtime available and records the attempted deployment as failed. Only one deployment runs for a given function. A newer request supersedes any queued request and starts after the running deployment. Different functions and projects deploy concurrently. If a function with the same name already exists in the project, this operation updates that function's runtime, handler, and source bundle and returns `200 OK`. Each project can contain up to 10,000 functions. Creating a new function over this cap returns 403. operationId: createFunction security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: multipart/form-data: schema: type: object required: - name - code - runtime properties: name: type: string description: DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen) maxLength: 63 pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ example: my-api-function code: type: string format: binary description: ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz source archive. runtime: type: string enum: - nodejs22.x - nodejs24.x - python3.10 - python3.11 - python3.12 - python3.13 - python3.14 - ruby3.3 - ruby3.4 - ruby4.0 description: | Runtime environment. Required. - Node.js: nodejs22.x, nodejs24.x - Python: python3.10, python3.11, python3.12, python3.13, python3.14 - Ruby: ruby3.3, ruby3.4, ruby4.0 example: nodejs24.x handler: type: string description: | The name of the function to invoke. Defaults to "handler" if not specified. Your code must export/define a function with this name: - Node.js: exports.handler (in index.js) - Python: def handler() (in main.py) - Ruby: def handler() (in main.rb) default: handler example: handler is_public: type: boolean description: | Whether the function can be reached through public invocation ingress. Omit it to keep the function's current visibility; a new function starts private. invocation_mode: $ref: '#/components/schemas/FunctionInvocationMode' http_auth_mode: $ref: '#/components/schemas/FunctionHTTPAuthMode' openapi_spec: type: string description: JSON-encoded OpenAPI 3.0 or 3.1 metadata for an HTTP-mode function. variable_scope: type: string enum: - all - scoped description: | Which project variables this function receives. `all` (the default) gives it only project variables marked `shared: true`; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged. variables: type: string description: | JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged. responses: '200': description: Existing function updated; its deployment was started or queued content: application/json: schema: $ref: '#/components/schemas/Function' '201': description: Function created and deployment workflow started content: application/json: schema: $ref: '#/components/schemas/Function' '400': description: Bad request (invalid file, too large, etc.) content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Function limit exceeded for the project content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | Function deletion is queued or running, or the name is already held by a durable function — a function cannot change kind. content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error (function deployment failed) content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/functions/{functionId}: get: tags: - Functions summary: Get function by ID operationId: getFunction security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FunctionId' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/Function' '404': description: Function not found content: application/json: schema: $ref: '#/components/schemas/Error' patch: tags: - Functions summary: Update function settings operationId: updateFunction security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FunctionId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateFunctionRequest' examples: makePublic: summary: Make function public (anon keys can invoke) value: is_public: true makePrivate: summary: Make function private (default behavior) value: is_public: false responses: '200': description: Function updated content: application/json: schema: $ref: '#/components/schemas/Function' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Function not found content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Functions summary: Delete a function description: | Schedules asynchronous function deletion. If another deployment is running, the function preserves its current status and exposes the queued deletion through `pending_deployment_id`. Its status changes to `deleting` when cleanup starts. After cleanup, it returns 404 and no longer appears in function lists. operationId: deleteFunction security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FunctionId' responses: '202': description: Function deletion started or queued '404': description: Function not found content: application/json: schema: $ref: '#/components/schemas/Error' /functions/{functionId}/invoke: post: tags: - Functions summary: Invoke a function description: | Invoke a serverless function. **With Service Key** (admin/background operations): - Use for background jobs, webhooks, cron, admin operations - Function receives payload only (no user context) - Database queries bypass RLS (admin access) **With Auth User Token** (user-facing): - Use for user-initiated actions - Function receives payload + `__volcano_auth` context: ```javascript { user_id: "uuid", email: "user@example.com", project_id: "uuid", role: "authenticated" or "anonymous" } ``` - Database queries enforce RLS (user-scoped data) **With Anon Key** (public function only): - Requires anon key permission: `functions.invoke` - Function must have `is_public: true` - Function receives payload only (no `__volcano_auth`) **Transport and CORS:** - This operation is the authenticated direct RPC endpoint and always uses the POST `{payload: ...}` contract, including for functions whose DNS ingress is configured in HTTP mode. - The geo-routed DNS ingress is the function's `invoke_url`. It is on a different domain from this API, so it cannot be derived from the API host. - RPC-mode DNS ingress accepts POST at `/`. HTTP-mode DNS ingress accepts GET, HEAD, POST, PUT, PATCH, and DELETE at `/` and nested paths. - Direct and RPC-mode CORS preflight advertises `POST, OPTIONS`. HTTP-mode DNS preflight advertises `GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS`. - `http_auth_mode: none` applies only to public HTTP-mode DNS ingress; this direct operation always requires a Volcano credential. **Durable functions are not invocable here.** A durable function's id answers 404, whatever its visibility, because a synchronous call would run it with no execution record, no idempotency and no concurrency accounting. Start one with `POST /durable-functions/{functionId}/executions`. operationId: invokeFunction security: - AnonKey: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/FunctionId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FunctionInvocationRequest' examples: serviceCall: summary: Admin/background operation (service key) value: payload: action: process_batch items: - 1 - 2 - 3 userCall: summary: User-initiated call (auth token) value: payload: action: get_profile anonCall: summary: Public function call (anon key) value: payload: action: ping_public_endpoint responses: '200': description: Function response (passthrough from function runtime) headers: X-Volcano-Version: description: Volcano API/runtime version that served this invocation (`` in production, `-` in non-production) schema: type: string X-Volcano-Region: description: Region the function ran in (for example `us-east-1`) schema: type: string content: application/json: schema: $ref: '#/components/schemas/FunctionInvocationResponse' '400': description: Bad request - invalid payload or function in failed state content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - CORS blocked, missing `functions.invoke`, or private function with anon key content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Function not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: | Rate limit exceeded (per-function or project-wide limit), or the owning platform user's billing-cycle bandwidth allowance (aggregate ingress + egress) was exceeded. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: | Function still provisioning or rate limiting service unavailable. A freshly deployed (or updated) function may briefly report `provisioning` and reject invocations until the background status reconciler observes its deployment workflow completing and transitions it to `active`. This is expected for a few seconds after deploy; clients should retry. content: application/json: schema: $ref: '#/components/schemas/Error' default: description: Function response (passthrough; status code/body/headers come from the function) headers: X-Volcano-Version: description: Volcano API/runtime version that served this invocation (`` in production, `-` in non-production) schema: type: string X-Volcano-Region: description: Region the function ran in (for example `us-east-1`) schema: type: string content: application/json: schema: $ref: '#/components/schemas/FunctionInvocationResponse' /durable-functions/{functionId}/executions: post: tags: - Durable Functions summary: Start a durable execution from an application description: | Starts an execution of a durable function using an application credential, and returns its handle. This is the durable counterpart of `POST /functions/{functionId}/invoke`, and it is the endpoint an application calls. Like that one, it is not project-scoped: an anon key, a service key and an auth user token each carry their own project. The project-scoped collection under `/projects/{id}/durable-functions/...` remains the owner's management surface. **With a service key or an auth user token:** any durable function in the project. **With an anon key:** requires the `functions.invoke` permission, and the function must have `is_public: true`. Starting is all this endpoint does. Reading a result or stopping an execution requires the project owner's token, because an anon key is shared by everyone who loads the page and an execution is addressed by id alone. Send `X-Volcano-Execution-Name` to make the start idempotent: repeating a start with the same name returns the existing execution instead of beginning a second one. Each execution counts once against the project's durable execution allowance, however many times the start is retried under the same execution name, and the number in flight at once is capped by the plan. The operations the execution performs are counted against the durable operations allowance when it finishes. operationId: startDurableExecutionFromApplication security: - AnonKey: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DurableFunctionId' - name: X-Volcano-Execution-Name in: header required: false description: | Idempotency key for this execution. Generated when omitted. A repeat under a name that already names a running execution returns that execution and is not charged again. Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything else is rejected with `400`. schema: type: string maxLength: 255 pattern: ^[A-Za-z0-9._-]+$ requestBody: required: false content: application/json: schema: description: Input passed to the function, up to 256 KiB. responses: '202': description: Execution accepted and started content: application/json: schema: $ref: '#/components/schemas/DurableExecution' '400': description: Payload is not valid JSON, or the execution name is invalid content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: | Missing or invalid credential. Also returned for a platform user token, which is not an application credential; project owners start executions through the project-scoped collection. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | The anon key lacks `functions.invoke`, the function is not public, or the request's origin is refused by the project's CORS policy. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: | Durable function not found. Also returned for a standard function's id and for a durable function in another project, so the response cannot be used to tell those apart. content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | Function is not deployed yet, or has no deployed region. Also returned when two starts under the same execution name raced and both released it, which is retryable as it stands. content: application/json: schema: $ref: '#/components/schemas/Error' '413': description: Payload is larger than 256 KiB content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: | The project has too many executions in flight for its plan, the function invocation rate limit was exceeded, the project is over its bandwidth cap, or the account is out of one of its billing-cycle durable allowances: executions, operations, or compute. Operations and compute are counted once an execution finishes, so a refusal on either never interrupts an execution already running — it declines the next start. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: | Durable execution is not available in this environment, or the usage limit service could not be reached to charge the start. The first is returned by a deployment that has no durable execution engine, such as a local one, and is not retryable there; the second is transient. content: application/json: schema: $ref: '#/components/schemas/Error' /functions/resolve: get: tags: - Functions summary: Resolve function name for invocation description: | Resolves a DNS-safe function name to its function ID and invocation URL within the caller's project. SDKs use this endpoint internally to invoke by function name while routing by function ID. Invoke the returned `invoke_url` as-is. It does not share a domain with the API, so a host built from the API URL will not reach the function. When the deployment serves no public invocation domain, as in local development, `invoke_url` is omitted and callers invoke through `POST /functions/{functionId}/invoke`. **With Service Key**: - Allowed **With Auth User Token**: - Allowed **With Anon Key**: - Requires anon key permission: `functions.invoke` - Function must have `is_public: true` operationId: resolveFunctionForInvocation security: - AnonKey: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - name: name in: query required: true schema: type: string maxLength: 63 pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ description: DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen) example: my-function responses: '200': description: Function resolved successfully content: application/json: schema: $ref: '#/components/schemas/ResolveFunctionResponse' '400': description: Bad request - missing or invalid function name content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - CORS blocked or missing `functions.invoke` permission for anon key content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: | Function not found (or private function with anon key). A durable function is never resolvable here: it is started through `POST /durable-functions/{functionId}/executions`, not invoked. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/logs/activity: post: tags: - Logs summary: Get project log activity description: | Retrieve bucketed log counts for one resource type in the project. Set `resource.type` to `function`, `frontend`, or `database`. Add `resource.ids` to filter to one or more resources, and add `resource.deployments.ids` to count deployment logs instead of runtime logs for functions and frontends. Deployment logs are not supported for databases. Database logs are a SUPERAGENT-plan feature; `resource.type=database` from a HOBBY-plan project owner returns 403. The activity window is limited to the plan's retention window (HOBBY: 1 day, SUPERAGENT: 30 days); older start times are clamped to that window. operationId: getProjectLogActivity security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/LogActivityRequest' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/LogActivityResponse' '400': description: Bad request - invalid query parameter content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or resource not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/logs/search: post: tags: - Logs summary: Search project logs description: | Search or filter logs for one resource type in the project. Set `resource.type` to `function`, `frontend`, or `database`. Add `resource.ids` to filter to one or more resources, and add `resource.deployments.ids` to read deployment logs instead of runtime logs for functions and frontends. Deployment logs are not supported for databases. Database logs are a SUPERAGENT-plan feature; requests for `resource.type=database` from a HOBBY-plan project owner return 403. Log history (runtime and deployment) is limited to the plan's retention window (HOBBY: 1 day, SUPERAGENT: 30 days); older time ranges are clamped to that window. operationId: searchProjectLogs security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/LogSearchRequest' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/LogSearchResponse' '400': description: Bad request - invalid query parameter content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or resource not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/logs/stream: post: tags: - Logs summary: Stream project logs description: | Live-tail project logs as Server-Sent Events. The request body uses the resource selector plus `q`, `start_time`, and `limit`, including runtime logs and function/frontend deployment logs selected with `resource.deployments`. Deployment logs are not supported for databases. Database logs are a SUPERAGENT-plan feature; `resource.type=database` from a HOBBY-plan project owner returns 403. The `q` field uses the same syntax as search and activity requests. Do not send `cursor` or `end_time`; use `/logs/search` for range backfills. Explicit historical `start_time` values are limited to the plan's retention window (HOBBY: 1 day, SUPERAGENT: 30 days). Resume with `Last-Event-ID` or the `last_event_id` query parameter. The cursor is bound to the request body: the resource selector and every filter must match the original request when reconnecting, otherwise the request is rejected with `400`. This is a live tail, not a gap-free backfill. On connect or reconnect the server delivers at most `limit` of the most recent matching events from the cursor position and then follows new events; events older than that window are not replayed. Use `/logs/search` to backfill a time range. operationId: streamProjectLogs security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: Last-Event-ID in: header required: false schema: type: string description: Opaque stream cursor from the most recent SSE `id` field. - name: last_event_id in: query required: false schema: type: string description: Opaque stream cursor fallback when setting `Last-Event-ID` is not practical. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/LogStreamRequest' responses: '200': description: Server-Sent Events stream. `log` events contain a JSON `LogSearchEvent`; `warning` events contain a JSON object with an `error` field. content: text/event-stream: schema: type: string examples: log: summary: Log event value: | : connected id: STREAM_CURSOR event: log data: {"id":"LOG_EVENT_ID","timestamp":"2024-01-01T12:00:00Z","level":"info","message":"User logged in","resource":{"type":"function","id":"550e8400-e29b-41d4-a716-446655440000","name":"login"},"region":"us-east-1"} '400': description: Bad request - invalid selector, stream cursor, or unsupported stream field content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or resource not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error - log streaming setup failed content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/functions/batch: post: tags: - Functions summary: Deploy multiple functions in one request description: | Upload multiple function source archives in one multipart request. Each archive should contain source files plus dependency manifests/lockfiles, not installed dependency directories. ZIP and tar.gz uploads are accepted and normalized to tar.gz before storage. The API enforces `SOURCE_ARCHIVE_SIZE_LIMIT_MB` for each uploaded and normalized source archive. The server records a shared deployment batch ID for the resulting function deployments. Each function deployment runs its own compile/publish workflow concurrently, and each publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` for the final container image. One batch request can include up to 100 functions. Submit multiple batch requests for larger projects. If one function fails before its workflow starts, already-started function deployments are left running and the failed function is reported in the `failed` array. Failed new functions are deleted; failed updates are rolled back to their previous metadata/status where possible. operationId: createFunctionsBatch security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: multipart/form-data: schema: type: object properties: functions: type: string description: | JSON array of functions with `name`, `runtime`, optional `handler`, and `file_field`. Each `file_field` must name a multipart file field containing that function's ZIP or tar.gz source bundle. Each entry may also declare `variable_scope` (`all` or `scoped`) and `variables` (an array of project variable names). Omitting them leaves the function's stored declaration unchanged. Volcano detects direct environment references in the uploaded source code and keeps them separate from the declared names: detected names are not written back to the declaration and do not appear in a config export. A scoped function receives its declared names plus the detected ones the project defines; a detected name the project does not define is ignored, since such a reference is often optional. Detection reads code only, so a name appearing solely in a comment or in an unrelated string is not a reference. Declare a name when the function reads it through a computed key, or when it must not deploy without the variable. The request is rejected with 400 before anything is deployed if a scoped function declares a variable the project does not define, or if the resulting environment exceeds 4096 bytes. code_0: type: string format: binary description: Function ZIP or tar.gz archive referenced by the first manifest entry's `file_field`; additional code_N file fields may be included. Each archive is subject to SOURCE_ARCHIVE_SIZE_LIMIT_MB. required: - functions responses: '202': description: Batch deployment accepted content: application/json: schema: $ref: '#/components/schemas/BatchFunctionDeployResponse' '207': description: Batch deployment partially accepted; successful functions started deployment and failed functions were compensated where possible content: application/json: schema: $ref: '#/components/schemas/BatchFunctionDeployResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Function limit exceeded for the project content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | A name in the batch is held by a function of the other kind — a function cannot change kind — or the project's source is managed by Git, where deploys come from a push to the production branch. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/schedulers: get: tags: - Functions summary: List every function scheduler in a project description: | Project-scoped counterpart to `/projects/{id}/functions/{functionId}/schedulers`. Returns schedulers across all functions in the project, ordered by creation time descending, with standard page/limit pagination so clients don't have to fan out one request per function. operationId: listProjectSchedulers security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' responses: '200': description: Project schedulers content: application/json: schema: $ref: '#/components/schemas/FunctionSchedulerListResponse' /projects/{id}/functions/{functionId}/schedulers: get: tags: - Functions summary: List schedulers for a function operationId: listFunctionSchedulers security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FunctionId' responses: '200': description: Function schedulers content: application/json: schema: $ref: '#/components/schemas/FunctionSchedulerListResponse' '404': description: Function not found content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Functions summary: Create a scheduler for a function description: Creates regional scheduled invocation jobs. Requested regions must be a subset of the function's deployed regions. operationId: createFunctionScheduler security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FunctionId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateFunctionSchedulerRequest' responses: '201': description: Scheduler created content: application/json: schema: $ref: '#/components/schemas/FunctionScheduler' '400': description: | Invalid schedule, geofenced region, a scheduler of this name already exists on the function, or the function is not active. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | Schedulers are not available on this plan, or the project already holds as many as the plan allows. The cap counts standard and durable function schedulers together. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Function not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/functions/{functionId}/schedulers/{schedulerId}: get: tags: - Functions summary: Get a function scheduler operationId: getFunctionScheduler security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FunctionId' - $ref: '#/components/parameters/SchedulerId' responses: '200': description: Function scheduler content: application/json: schema: $ref: '#/components/schemas/FunctionScheduler' '404': description: Function or scheduler not found content: application/json: schema: $ref: '#/components/schemas/Error' patch: tags: - Functions summary: Update a function scheduler operationId: updateFunctionScheduler security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FunctionId' - $ref: '#/components/parameters/SchedulerId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateFunctionSchedulerRequest' responses: '200': description: Scheduler updated content: application/json: schema: $ref: '#/components/schemas/FunctionScheduler' '400': description: | Invalid schedule, geofenced region, or a scheduler of this name already exists on the function. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Function or scheduler not found content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Functions summary: Delete a function scheduler operationId: deleteFunctionScheduler security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FunctionId' - $ref: '#/components/parameters/SchedulerId' responses: '204': description: Scheduler deleted '404': description: Function or scheduler not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/functions/{functionId}/deployments: get: tags: - Functions summary: List function deployments operationId: listFunctionDeployments security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FunctionId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedFunctionDeployments' '404': description: Function not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/durable-functions: get: tags: - Durable Functions summary: List all durable functions in a project description: | Standard functions never appear here, and durable functions never appear under `/projects/{id}/functions`. The two are separate collections. operationId: listDurableFunctions security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Search' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedDurableFunctions' '400': description: Bad request - invalid pagination parameters content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Durable Functions summary: Create or update a durable function description: | Upload a durable function source bundle. Creates the function on the first call for a name and redeploys it on every call after that, the same create-or-update contract `POST /projects/{id}/functions` has. Volcano builds and deploys asynchronously. A deployment that starts immediately returns `status: provisioning`, then transitions to `active` or `failed`; a deployment that has to wait for a running one is exposed through `pending_deployment_id`. Existing executions keep running against the runtime they started on. The `durable` configuration is derived from the project's plan rather than supplied here, and is fixed once the function exists. A name already held by a standard function is rejected with 409: a function cannot change kind. operationId: createDurableFunction security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: multipart/form-data: schema: type: object required: - name - code - runtime properties: name: type: string description: DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen) maxLength: 63 pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ example: order-pipeline code: type: string format: binary description: ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles. runtime: type: string enum: - nodejs22.x - nodejs24.x - python3.13 - python3.14 description: | Runtime environment. Required. Durable execution needs the durable authoring API, which ships for these runtimes only; any other runtime is rejected with 400 and the response names the ones that work. Note that a durable Python function needs a newer runtime than a standard one defaults to. `GET /functions/runtimes` reports `durable_capable` per runtime. example: nodejs24.x handler: type: string description: The name of the function to invoke. Defaults to "handler" if not specified. default: handler example: handler is_public: type: boolean description: | Whether anon keys with `functions.invoke` may start an execution. Redeploying is the only way to change it, since the collection has no update endpoint; omit it to keep the current visibility, and a new function starts private. The standard collection's synchronous invocation fields — `invocation_mode`, `http_auth_mode`, `openapi_spec` — configure a request path no durable route serves, and are rejected with 400 rather than ignored. variable_scope: type: string enum: - all - scoped description: | Which project variables this function receives. `all` (the default) gives it every project variable; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged. variables: type: string description: | JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged. responses: '200': description: Existing durable function updated; its deployment was started or queued content: application/json: schema: $ref: '#/components/schemas/DurableFunction' '201': description: Durable function created and deployment workflow started content: application/json: schema: $ref: '#/components/schemas/DurableFunction' '400': description: | Bad request (invalid archive, unsupported runtime, invalid name, or a project region that does not offer durable execution — a durable function deploys to every region of its project) content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Durable function limit exceeded for the project content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Name is held by a standard function, or a deletion is queued or running content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error (function deployment failed) content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: | Durable deploys are paused platform-wide. The same request succeeds once they are re-enabled; executions already running are unaffected. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/durable-functions/{functionId}: get: tags: - Durable Functions summary: Get durable function by ID or name operationId: getDurableFunction security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DurableFunction' '404': description: Durable function not found content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Durable Functions summary: Delete a durable function description: | Accepted for asynchronous teardown; the work continues after the response. The function's executions go with it: history stops being readable whatever `retention_days` had left, and the executions still running stop counting against the project's concurrency cap. Stop an execution first if you need it to end before the function does. operationId: deleteDurableFunction security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' responses: '202': description: Deletion accepted and teardown started '404': description: | Durable function not found. Also returned for an id that names a durable function in another project, so the response cannot be used to tell the two apart. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/durable-functions/{functionId}/deployments: get: tags: - Durable Functions summary: List durable function deployments operationId: listDurableFunctionDeployments security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedFunctionDeployments' '404': description: Durable function not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/durable-functions/{functionId}/schedulers: get: tags: - Durable Functions summary: List schedulers for a durable function description: | The durable collection's counterpart to `/projects/{id}/functions/{functionId}/schedulers`. A standard function's id is not accepted here, and a durable function's id is not accepted there. operationId: listDurableFunctionSchedulers security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' responses: '200': description: Durable function schedulers content: application/json: schema: $ref: '#/components/schemas/FunctionSchedulerListResponse' '404': description: Durable function not found content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Durable Functions summary: Create a scheduler for a durable function description: | Each tick starts an execution rather than invoking the function, under an execution name derived from the run, so a retried tick resolves to the execution it already started. Requested regions must be a subset of the function's deployed regions. A tick draws on the same durable allowances and concurrency cap a manual start does, and a tick that would exceed the cap fails that run. operationId: createDurableFunctionScheduler security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateFunctionSchedulerRequest' responses: '201': description: Scheduler created content: application/json: schema: $ref: '#/components/schemas/FunctionScheduler' '400': description: | Invalid schedule, geofenced region, a scheduler of this name already exists on the function, or the function is not active. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | Schedulers are not available on this plan, or the project already holds as many as the plan allows. The cap counts standard and durable function schedulers together. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Durable function not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/durable-functions/{functionId}/schedulers/{schedulerId}: get: tags: - Durable Functions summary: Get a durable function scheduler operationId: getDurableFunctionScheduler security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' - $ref: '#/components/parameters/SchedulerId' responses: '200': description: Durable function scheduler content: application/json: schema: $ref: '#/components/schemas/FunctionScheduler' '404': description: Durable function or scheduler not found content: application/json: schema: $ref: '#/components/schemas/Error' patch: tags: - Durable Functions summary: Update a durable function scheduler operationId: updateDurableFunctionScheduler security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' - $ref: '#/components/parameters/SchedulerId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateFunctionSchedulerRequest' responses: '200': description: Scheduler updated content: application/json: schema: $ref: '#/components/schemas/FunctionScheduler' '400': description: | Invalid schedule, geofenced region, or a scheduler of this name already exists on the function. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Durable function or scheduler not found content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Durable Functions summary: Delete a durable function scheduler operationId: deleteDurableFunctionScheduler security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' - $ref: '#/components/parameters/SchedulerId' responses: '204': description: Scheduler deleted '404': description: Durable function or scheduler not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/durable-functions/{functionId}/executions: post: tags: - Durable Functions summary: Start a durable execution description: | Starts an execution and returns its handle. Never returns a result: an execution can outlive any request a client could hold open, so the result is read back from `GET /projects/{id}/durable-functions/{functionId}/executions/{executionId}`. The request body is the execution's input and must be valid JSON if present. An empty body starts the execution with no input. Send `X-Volcano-Execution-Name` to make the start idempotent: repeating a start with the same name returns the existing execution instead of beginning a second one. Each execution counts against the project's durable execution allowance, the operations it performs count against the durable operations allowance when it finishes, and the number of executions in flight at once is capped by the plan. operationId: startDurableExecution security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' - name: X-Volcano-Execution-Name in: header required: false description: | Idempotency key for this execution. Generated when omitted. A repeat under a name that already names a running execution returns that execution and is not charged again. Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything else is rejected with `400`. schema: type: string maxLength: 255 pattern: ^[A-Za-z0-9._-]+$ requestBody: required: false content: application/json: schema: description: Input passed to the function, up to 256 KiB. responses: '202': description: Execution accepted and started content: application/json: schema: $ref: '#/components/schemas/DurableExecution' '400': description: Payload is not valid JSON, or the execution name is invalid content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Durable function not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | Function is not deployed yet, or has no deployed region. Also returned when two starts under the same execution name raced and both released it, which is retryable as it stands. content: application/json: schema: $ref: '#/components/schemas/Error' '413': description: Payload exceeds the maximum execution input size content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: | Too many executions already in flight for this project, or the account is out of one of its billing-cycle durable allowances: executions, operations, or compute. An owner-started execution is metered exactly like an application-started one. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: | Durable execution is not available in this environment, or the usage limit service could not be reached to charge the start. The first is returned by a deployment that has no durable execution engine, such as a local one, and is not retryable there; the second is transient. content: application/json: schema: $ref: '#/components/schemas/Error' get: tags: - Durable Functions summary: List a durable function's executions description: | Returns the platform's last observed status for each execution; listing does not poll each one. Fetch a single execution for its live state. operationId: listDurableExecutions security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - name: status in: query required: false description: Return only executions in this status. schema: $ref: '#/components/schemas/DurableExecutionStatus' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedDurableExecutions' '400': description: Unsupported status filter content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Durable function not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/durable-functions/{functionId}/executions/{executionId}: get: tags: - Durable Functions summary: Get a durable execution description: | Returns the execution's current state, including its `result` once it has succeeded. Poll this to wait for an execution to finish. operationId: getDurableExecution security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' - $ref: '#/components/parameters/DurableExecutionId' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DurableExecution' '404': description: Durable function or execution not found content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: | Durable execution is not available in this environment. Returned by a deployment that has no durable execution engine, such as a local one; the request is not retryable there. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/durable-functions/{functionId}/executions/{executionId}/stop: post: tags: - Durable Functions summary: Stop a durable execution description: | Cancels a running execution. Its completed steps are not undone. The call is accepted rather than awaited: cancellation happens behind it, so the response reports the execution as it was read back and may still say `running`. Do not branch on that status — the execution settles into `stopped` shortly after, and polling `GET /projects/{id}/durable-functions/{functionId}/executions/{executionId}` is how you see it get there. Stopping an execution that already finished is not an error: the response carries the state it settled in. operationId: stopDurableExecution security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DurableFunctionId' - $ref: '#/components/parameters/DurableExecutionId' responses: '200': description: | Stop accepted. The body is the execution as it was read back, which may still report `running`. content: application/json: schema: $ref: '#/components/schemas/DurableExecution' '404': description: Durable function or execution not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Execution has not started yet content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: | Durable execution is not available in this environment. Returned by a deployment that has no durable execution engine, such as a local one; the request is not retryable there. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/frontends: get: tags: - Frontends summary: List all frontends in a project description: | Supports two mutually exclusive pagination modes. Offset mode uses `page` and `limit` and returns `next` (URL). Cursor mode uses `cursor` and `limit`, supports `search` (case-insensitive name match), and returns `next_cursor`. Sending both `page` and `cursor` (or `page` and `search`) returns 400. operationId: listFrontends security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedFrontends' '400': description: Bad request - invalid project identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Frontends summary: Create a new frontend deployment description: | Creates and deploys a frontend for the project. If a frontend with the same name already exists in the project, this operation updates that frontend using the uploaded archive and starts a new deployment. A deployment that starts immediately returns `status: provisioning`, then transitions to `active`, `degraded`, or `failed`. If another deployment is running, the response preserves the frontend's current status and exposes the queued deployment through `pending_deployment_id`. Existing frontend traffic continues to use an available runtime while the new deployment builds and provisions. Each deployment publishes its own static assets before the runtimes switch to its build, and the live build's assets keep serving until the new deployment is live, so a page loaded mid-deployment resolves its assets whichever build served it. A failed redeploy puts the runtimes back on the build they were running, leaves the frontend `active` on the previous deployment, and records the attempted deployment as failed. `degraded` means the runtime remains available but edge synchronization requires recovery; Volcano retries the edge step without rebuilding. Only one deployment may run for a given frontend, while independent frontends and projects can deploy concurrently. For monorepos, provide `app_root` as a relative path from the uploaded archive root to the Next.js app that should be built. Omit it for single-app archives. Supported frontend environments are Next.js 15.x and 16.x with Node.js 22.x or 24.x. The Node.js runtime is inferred from `package.json` `engines.node`; if omitted, Volcano uses Node.js 22.x. The selected Node.js family must also satisfy the installed Next.js package's `engines.node` constraint. Volcano tests Next 15.5.25 (`^18.18.0 || ^19.8.0 || >=20.0.0`) and Next 16.3.5 (`>=20.9.0`). Source archive size is enforced by the API with `SOURCE_ARCHIVE_SIZE_LIMIT_MB`; the CLI does not apply its own source archive size limit. After the final container images are built, the publish build enforces `LAMBDA_TARGET_CONTAINER_SIZE_LIMIT_MB` before pushing. This operation is limited by plan-based frontend deployment quotas (`FREE_FRONTEND_DEPLOYMENTS`, `PRO_FRONTEND_DEPLOYMENTS`). Each project can contain up to 10,000 frontends regardless of plan. operationId: createFrontend security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: multipart/form-data: schema: type: object required: - name - archive properties: name: type: string maxLength: 63 pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ description: DNS-safe frontend name framework: type: string enum: - nextjs default: nextjs description: Next.js frontend. Supported Next.js majors are 15.x and 16.x. app_root: type: string maxLength: 1024 description: Optional relative POSIX path from the uploaded archive root to the Next.js app to build, for example `apps/web`. example: apps/web archive: type: string format: binary description: ZIP or tar.gz archive of the frontend project directory or monorepo workspace root. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz archive. responses: '200': description: Existing frontend updated; its deployment was started or queued content: application/json: schema: $ref: '#/components/schemas/Frontend' '201': description: Frontend created and deployment workflow started content: application/json: schema: $ref: '#/components/schemas/Frontend' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Frontend deployment limit exceeded for the current plan or project hard cap content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Conflict - frontend deletion is queued or running content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Service unavailable - frontend workflow or archive limit configuration missing content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/frontends/{frontendId}: get: tags: - Frontends summary: Get frontend details operationId: getFrontend security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/Frontend' '400': description: Bad request - invalid identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Frontend not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Frontends summary: Delete a frontend description: | Schedules asynchronous frontend deletion. If another deployment is running, the frontend preserves its current status and exposes the queued deletion through `pending_deployment_id`. Its status changes to `deleting` when cleanup starts. After cleanup, it returns 404 and no longer appears in frontend lists. operationId: deleteFrontend security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' responses: '202': description: Frontend deletion started or queued '400': description: Bad request - invalid identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Frontend not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Service unavailable - frontend workflow configuration missing content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/frontends/{frontendId}/redeploy: post: tags: - Frontends summary: Redeploy frontend using latest uploaded artifact description: | Starts a new frontend workflow using the latest stored artifact. A deployment that starts immediately returns `status: provisioning`, then transitions to `active`, `degraded`, or `failed`. An overlapping deployment preserves the frontend's current status, is exposed through `pending_deployment_id`, and supersedes any older queued deployment. The previous runtime and its published static assets remain available during provisioning, and a failed redeploy restores the regional runtimes to that build and keeps it serving while the attempted deployment is recorded as failed. operationId: redeployFrontend security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' responses: '200': description: Frontend redeploy started or queued content: application/json: schema: $ref: '#/components/schemas/Frontend' '400': description: Bad request - invalid identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Frontend not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Conflict - frontend deletion is queued or running content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Service unavailable - frontend workflow configuration missing content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/frontends/{frontendId}/domain: get: tags: - Frontends summary: Get frontend custom domain status operationId: getFrontendCustomDomain security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' responses: '200': description: | Frontend custom domain status, or null when the frontend has no custom domain configured (the common empty state). content: application/json: schema: nullable: true allOf: - $ref: '#/components/schemas/FrontendCustomDomainResponse' '400': description: Bad request - invalid identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Frontend not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Frontends summary: Configure frontend custom domain (SUPERAGENT) description: | Configures one custom domain for a frontend. The default Volcano-generated frontend URL remains active. Wildcard Volcano frontend TLS remains valid and isolated from custom-domain certificate changes. Managed TLS returns the DNS records currently required for setup. Volcano may require a tenant-specific TXT ownership challenge before returning the certificate authority's validation record. After ownership verification succeeds, Volcano permanently assigns the hostname to the account, including after the domain is deleted. A required but unverified ownership reservation expires after 72 hours. An unverified reservation does not block an account that proves ownership. When another account holds one, a managed TLS request gets `409` with `code: ownership_verification_required` and the caller's own `required_record`; after publishing it, the same request takes over the reservation. A BYOC request with a publicly trusted certificate and key for the hostname also takes it over; other BYOC requests get a `409` without `code`. Hostnames claimed through ownership verification and BYOC domains are never taken over. operationId: createFrontendCustomDomain security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateFrontendCustomDomainRequest' responses: '200': description: Custom domain already configured with same hostname content: application/json: schema: $ref: '#/components/schemas/FrontendCustomDomainResponse' '201': description: Custom domain provisioning started content: application/json: schema: $ref: '#/components/schemas/FrontendCustomDomainResponse' '400': description: Bad request - invalid domain content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - custom domains require SUPERAGENT plan content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Frontend not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Conflict - custom domain already in use, reserved by another account until ownership is proven, still detaching, or frontend already has a custom domain content: application/json: schema: $ref: '#/components/schemas/FrontendCustomDomainConflictError' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Service unavailable - custom domain provisioning is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Frontends summary: Delete frontend custom domain operationId: deleteFrontendCustomDomain security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' responses: '204': description: Custom domain detach scheduled '400': description: Bad request - invalid identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Frontend or custom domain not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/frontends/{frontendId}/deployments: get: tags: - Frontends summary: List frontend deployments operationId: listFrontendDeployments security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedFrontendDeployments' '400': description: Bad request - invalid identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Frontend not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/frontends/{frontendId}/usage: get: tags: - Frontends summary: Per-day request and error counts for a single frontend description: | Returns a zero-filled daily series of request counts and 5xx error counts for one frontend, oldest first. Each entry is one UTC day; missing days (no traffic recorded) come back as `requests: 0, errors: 0` so the response always has exactly `days` entries. Backs the Monitoring section on the Frontend detail page in volcano-web. `days` defaults to 30 and is capped at 90 to keep the (frontend_id, day) index scan bounded. operationId: getFrontendUsageHistory security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/FrontendId' - name: days in: query description: Number of trailing days to return (1–90, default 30). required: false schema: type: integer minimum: 1 maximum: 90 default: 30 responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/FrontendUsageHistoryResponse' '400': description: Bad request - invalid identifier content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Forbidden - project ownership required content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Frontend not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/variables: get: tags: - Variables summary: List all variables for a project description: | Returns project-level environment variables used by deployed functions and frontends. operationId: listVariables security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedVariables' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Variables summary: Create or update a variable description: | Creates a project-level environment variable and triggers asynchronous propagation to deployed functions and frontends in the project's configured regions. operationId: createVariable security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateVariableRequest' responses: '201': description: Variable created content: application/json: schema: $ref: '#/components/schemas/Variable' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Private variable membership writes are disabled during rollout content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases: get: tags: - Databases summary: List all databases for a project description: | Supports two mutually exclusive pagination modes. Offset mode uses `page` and `limit`. Cursor mode uses `cursor` and `limit`, supports `search` (case-insensitive name match), and returns `next_cursor`/`prev_cursor`. The optional `status` filter applies in both modes and is bound to the cursor. Sending both `page` and `cursor` (or `page` and `search`) returns 400. operationId: listDatabases security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' - name: status in: query required: false schema: type: string enum: - provisioning - active - restoring - failed - deleting description: Return only the databases in this status. responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedDatabases' post: tags: - Databases summary: Create a new serverless PostgreSQL database description: | Creates a serverless PostgreSQL database in the project. Each project can hold 1 database on Hobby and up to 10,000 on Superagent. Requests over the plan's cap return 403. operationId: createDatabase security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateDatabaseRequest' responses: '201': description: Database created (provisioning) content: application/json: schema: $ref: '#/components/schemas/Database' '403': description: Database limit exceeded for the project content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}: get: tags: - Databases summary: Get database details operationId: getDatabase security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/Database' delete: tags: - Databases summary: Delete a database description: | Deletes a database and the instance backing it. When the instance is removed synchronously the database row is deleted and the response is `204`. If the instance cannot be deleted right away, the database row is retained (status `deleting`) and its teardown is handed to the background reconciler, which retries the deletion and removes the row once the instance is gone; in that case the response is `202`. The database row is never dropped while its instance still exists, so an instance is never orphaned without a record to retry from. operationId: deleteDatabase security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' responses: '202': description: | Deletion accepted and in progress. The backing instance could not be removed synchronously, so the database is marked `deleting` and torn down asynchronously by the reconciler. content: application/json: schema: type: object properties: status: type: string example: deleting message: type: string example: database deletion in progress '204': description: Database deleted (backing instance removed synchronously) '404': description: Project or database not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | A restore is running on the database. Deleting it while a worker is replacing its data would race that worker, so wait for the restore to finish. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: | Volcano could not check whether a restore is running, and will not delete a database that might be mid-restore. Retry. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/branches: get: tags: - Database Branches summary: List a database's branches description: | Returns every branch of the database, including those still provisioning and those that failed, since each still holds a name. Connection strings are omitted. Fetch a single branch to get its connection string. operationId: listDatabaseBranches security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DatabaseBranchList' '404': description: Project or database not found content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Branching is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Database Branches summary: Create a branch of a database description: | Forks the database into a new branch. The branch starts as an exact copy of the parent's data and diverges from there. Provisioning is asynchronous: the response is `202` with the branch in `provisioning` and no connection string. Poll the branch until it reports `active`, at which point it carries its own connection string. Retrying a create with a name that already exists returns `409` rather than a second branch, so a retried request cannot silently consume two slots of the branch allowance. operationId: createDatabaseBranch security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateDatabaseBranchRequest' responses: '202': description: Branch accepted and provisioning content: application/json: schema: $ref: '#/components/schemas/DatabaseBranch' '400': description: Invalid branch name or lifetime content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | The database has reached its branch allowance, or the owner's plan does not include branching. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or database not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | A branch of that name already exists on this database, or the database cannot be branched right now because it is still provisioning, being restored, failed, or being deleted. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Branching is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/branches/{branchName}: get: tags: - Database Branches summary: Get a branch description: | Returns the branch, including its connection string once it is `active`. Poll this after creating a branch to learn when it is connectable. operationId: getDatabaseBranch security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DatabaseBranch' '404': description: Project, database, or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Branching is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' patch: tags: - Database Branches summary: Extend a branch's lifetime description: | Replaces the branch's lifetime and restarts the countdown from now, so a branch you are still working on is not swept mid-session. The new duration is remembered, so a later reset re-arms the same lifetime. operationId: updateDatabaseBranch security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateDatabaseBranchRequest' responses: '200': description: Lifetime updated content: application/json: schema: $ref: '#/components/schemas/DatabaseBranch' '400': description: Requested lifetime is outside the allowed range content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project, database, or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: The branch is being deleted content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Branching is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Database Branches summary: Delete a branch description: | Marks the branch for teardown and returns immediately. The branch stops accepting connections at once; its fork and its row are removed by a background job, so a provider outage cannot leave the call hanging or the branch half-deleted. Deleting a branch that is still provisioning is allowed and stops the build, and repeating the call while teardown is in progress is accepted again. Once the branch is gone the call returns `404`. operationId: deleteDatabaseBranch security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' responses: '202': description: Deletion accepted and in progress content: application/json: schema: type: object properties: status: type: string example: deleting message: type: string example: branch deletion in progress required: - status - message '404': description: Project, database, or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Branching is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/branches/{branchName}/reset: post: tags: - Database Branches summary: Reset a branch to its parent's current state description: | Discards everything written on the branch and re-forks it from the parent as it is now. Returns immediately with the branch in `provisioning`. The rewind runs in the background; poll the branch until it reports `active` before connecting again. The branch keeps its name and its connection string, so anything holding that string keeps working once it is active again, and its lifetime is re-armed to the duration it was created with. The branch does not serve connections for the duration of the reset. operationId: resetDatabaseBranch security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' responses: '202': description: Branch reset accepted; the branch is provisioning content: application/json: schema: $ref: '#/components/schemas/DatabaseBranch' '404': description: Project, database, or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | The branch is not active, a reset is already in progress, the parent database is being restored, or the parent was restored within the last 24 hours — a reset re-forks from the parent, and the provider holds a child's reset shut for that long afterwards. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Branching is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/branches/{branchName}/reset-password: post: tags: - Database Branches summary: Rotate a branch's password description: | Issues a new password for the branch and invalidates the previous connection string. Existing connections are not interrupted; new ones must use the returned string. Proxies pick the rotation up within a few seconds, so the previous password can still open new connections until then. The parent database's credentials are untouched. operationId: resetDatabaseBranchPassword security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' responses: '200': description: Password rotated content: application/json: schema: $ref: '#/components/schemas/DatabaseBranch' '404': description: Project, database, or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: The branch is not active content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Branching is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/backups: get: tags: - Database Backups summary: List a database's backups description: | Returns every backup of the database, newest first, together with the window a point-in-time restore may target. Both backups you took and backups the schedule produced are listed; `source` tells them apart. Only manual backups count against the plan's backup allowance. operationId: listDatabaseBackups security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DatabaseBackupList' '403': description: Backups are SUPERAGENT-only and the owner's plan does not include them content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or database not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | The database has no storage project yet, so there is nothing to list. A database reports this while it is still provisioning. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Backups are temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Database Backups summary: Back up a database description: | Captures the database as it is now. The backup is available immediately; its `size_bytes` appears once the storage provider has costed it. Backups are rate-limited to one per minute per database, and capped by the owner's plan. operationId: createDatabaseBackup security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateDatabaseBackupRequest' responses: '201': description: Backup created content: application/json: schema: $ref: '#/components/schemas/DatabaseBackup' '400': description: Invalid backup name content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | The database has reached its backup allowance, or the owner's plan does not include backups, which are SUPERAGENT-only. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or database not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | A backup of that name already exists, the database is not active, a restore is running on it, or a backup was taken too recently. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Backups are temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/backups/{backupName}: get: tags: - Database Backups summary: Get a backup description: Returns one backup of the database. operationId: getDatabaseBackup security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BackupName' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DatabaseBackup' '403': description: Backups are SUPERAGENT-only and the owner's plan does not include them content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project, database, or backup not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | The database has no storage project yet, so it holds no backups. A database reports this while it is still provisioning. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Backups are temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Database Backups summary: Delete a backup description: | Deletes the backup and frees its storage. Scheduled backups can be deleted too. A backup that is already gone reports `404`, so a name that never existed and a name that no longer does read the same. Refused with `409` while the database is being restored. operationId: deleteDatabaseBackup security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BackupName' responses: '200': description: Backup deleted content: application/json: schema: type: object properties: status: type: string example: deleted message: type: string example: backup deleted required: - status - message '403': description: Backups are SUPERAGENT-only and the owner's plan does not include them content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project, database, or backup not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | The database is being restored. A restore is pinned to a backup it may not have restored yet, so deleting one is refused until the restore finishes. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Backups are temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/backup-schedule: get: tags: - Database Backups summary: Get the automated backup schedule description: | Returns the database's backup schedule. An empty list means no scheduled backups. operationId: getDatabaseBackupSchedule security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DatabaseBackupSchedule' '403': description: Backups are SUPERAGENT-only and the owner's plan does not include them content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or database not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | The database has no storage project yet, so it has no schedule. A database reports this while it is still provisioning. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Backups are temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' put: tags: - Database Backups summary: Replace the automated backup schedule description: | Replaces the schedule wholesale. Send an empty `entries` list to stop scheduled backups. Scheduled backups do not count against the plan's backup allowance, but their retention is clamped to the plan's. operationId: updateDatabaseBackupSchedule security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DatabaseBackupSchedule' responses: '200': description: Schedule replaced content: application/json: schema: $ref: '#/components/schemas/DatabaseBackupSchedule' '400': description: | The schedule names a recurrence that cannot fire: a weekly or monthly one with no `day`, or a `day` outside its frequency's range (1-7 for weekly, 1-28 for monthly). The response says which. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Backups are SUPERAGENT-only and the owner's plan does not include them content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or database not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | The database is not active, or a restore is running on it — a restore moves the data to a new branch, and the provider keeps the schedule per branch. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Backups are temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/restores: get: tags: - Database Backups summary: List a database's restores description: | Returns the database's restore history, newest first, capped at the 50 most recent. There is no pagination: a database that has been restored more than 50 times keeps the older records but does not return them. operationId: listDatabaseRestores security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DatabaseRestoreList' '403': description: Backups are SUPERAGENT-only and the owner's plan does not include them content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or database not found content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Backups are temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Database Backups summary: Restore a database description: | Replaces the database's data, either with a named backup or with its state at a point in time. This is destructive: everything written after that point is discarded. Asynchronous: the response is `202` with the restore `pending` and the database `restoring`. The database does not accept connections until the restore reports `completed`; its connection string is unchanged throughout, so nothing holding it needs updating. Restores are in place. There is no way to restore into a second database, and a database's branches are never restored — they keep serving their own data, but resetting a branch from its parent is refused by the storage provider for up to 24 hours afterwards. operationId: createDatabaseRestore security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateDatabaseRestoreRequest' responses: '202': description: Restore accepted and in progress content: application/json: schema: $ref: '#/components/schemas/DatabaseRestore' '400': description: | Neither or both restore targets were named, or the requested time is outside the available window. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | The owner's plan does not include backups or point-in-time restore. Both are SUPERAGENT-only. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project, database, or backup not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | A restore is already in progress, the database is not active, another database operation is still running, or the database is holding as many pre-restore branches as it may. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Backups are temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/restores/{restoreId}: get: tags: - Database Backups summary: Get a restore description: | Returns the restore. Poll this after starting one; the database is connectable again once it reports `completed`. operationId: getDatabaseRestore security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/RestoreId' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DatabaseRestore' '403': description: Backups are SUPERAGENT-only and the owner's plan does not include them content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project, database, or restore not found content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Backups are temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/reset-password: post: tags: - Databases summary: Reset database password description: | Rotates the Volcano-managed PostgreSQL password used by clients when connecting through pgproxy. This does not rotate or expose the internal owner password. The returned password and connection string are the only client credentials that will authenticate through pgproxy after reset. Existing connections are not interrupted; new ones must use the returned string. Proxies pick the rotation up within a few seconds, so the previous password can still open new connections until then. operationId: resetDatabasePassword security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' responses: '200': description: Password reset successful content: application/json: schema: type: object properties: message: type: string role_name: type: string description: Volcano-managed per-database client login (also the pgproxy routing username) example: volcano_client_11111111-1111-1111-1111-111111111111 new_password: type: string description: New Volcano-managed client password. Always starts with `vpg_`. connection_string: type: string description: Updated pgproxy connection string using Volcano-managed credentials. '400': description: Database is not active content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database not found content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | A restore is running on the database. A restore replaces the credentials as it finishes, so wait for it and rotate afterwards. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: | Volcano could not check whether a restore is running, and will not rotate a credential a restore might be about to replace. Retry. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/type: patch: tags: - Databases summary: Update database size description: | Change the size tier of a database. This may briefly interrupt active connections. **Available sizes:** - `volcano-db-xs`: Up to ~1GB RAM - Development, small apps - `volcano-db-s`: Up to ~4GB RAM - Production-ready, light traffic - `volcano-db-m`: Up to ~8GB RAM - Medium traffic applications - `volcano-db-l`: Up to ~16GB RAM - High traffic, larger datasets - `volcano-db-xl`: Up to ~32GB RAM - Heavy workloads - `volcano-db-2xl`: Up to ~64GB RAM - Enterprise-scale operationId: updateDatabaseType security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateDatabaseTypeRequest' responses: '200': description: Database type updated content: application/json: schema: $ref: '#/components/schemas/Database' '400': description: Invalid database type '404': description: Database not found '409': description: | The database is not active — being provisioned, deleted, or restored. Compute can only be changed while it is active. content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: | Volcano could not check whether a restore is running, and will not reconfigure compute a restore might be moving. Retry. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/databases/{databaseName}/stats: get: tags: - Databases summary: Get database consumption metrics description: | Retrieve consumption metrics including storage, compute time, and data transfer. Metrics are aggregated at the project level. Defaults to last 24 hours. **Note:** Advanced metrics require an upgraded plan. operationId: getDatabaseStats security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/DatabaseName' - name: from in: query required: false schema: type: string format: date-time description: Start time in RFC3339 format (e.g., "2024-01-01T00:00:00Z"). Defaults to 24 hours ago. - name: to in: query required: false schema: type: string format: date-time description: End time in RFC3339 format (e.g., "2024-01-02T00:00:00Z"). Defaults to now. - name: granularity in: query required: false schema: type: string enum: - hourly - daily - monthly default: hourly description: Level of detail for metrics aggregation responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/DatabaseStats' '400': description: Invalid parameters content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database not found content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Database metrics not available or requires upgraded plan content: application/json: schema: $ref: '#/components/schemas/Error' /databases/{databaseName}/query/ping: post: tags: - Database Queries summary: Database connectivity probe (REST API) description: | Connectivity probe that runs a fixed `SELECT 1` through pgproxy, using the same authentication, status/bandwidth gating, and metering as the other `/query/*` endpoints. Unlike those endpoints, ping takes **no request body** and performs **no table-name validation**, so it works on any database — including a freshly provisioned, empty one. It is a real committed round-trip through pgproxy, so a `200` means the database is reachable and queryable. Used by the dashboard's database connection test. operationId: queryDatabasePing security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' responses: '200': description: Database is reachable content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - '?column?': 1 count: 1 '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' /databases/{databaseName}/query/select: post: tags: - Database Queries summary: Query database with SELECT (REST API) description: | Query your database using a simple REST API - no SQL required! **Authentication:** Requires auth user access token (from signup/signin) **Row-Level Security:** Automatically enforced - you see only data you have access to **Use Cases:** - Query from browser/mobile apps - Simple data retrieval - Filtered searches with sorting and pagination **Note:** For complex queries (JOINs, CTEs), use functions with direct SQL operationId: queryDatabaseSelect security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DatabaseSelectRequest' responses: '200': description: Query successful content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - id: uuid-123 title: My Post content: Post content status: published views: 150 created_at: '2026-01-13T10:00:00Z' count: 1 '400': description: Invalid query content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' /databases/{databaseName}/query/insert: post: tags: - Database Queries summary: Insert data into database (REST API) description: | Insert new rows into your database using REST API. **Authentication:** Requires auth user access token **Auto-set user_id:** If your table has a trigger using `auth.uid()`, user_id will be automatically set to the authenticated user **Security:** Row-Level Security policies are enforced operationId: queryDatabaseInsert security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DatabaseInsertRequest' responses: '200': description: Insert successful content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - id: uuid-123 title: My New Post content: This is the content status: draft user_id: user-uuid created_at: '2026-01-13T10:00:00Z' count: 1 '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' /databases/{databaseName}/query/update: post: tags: - Database Queries summary: Update data in database (REST API) description: | Update existing rows in your database using REST API. **Security:** Row-Level Security ensures you can only update data you have access to **Safety:** Requires at least one filter to prevent accidental mass updates. A request with no `filters` is rejected with `400` (mirrors delete). This matters for service-key queries, which run with full access and bypass RLS. **Note:** If RLS blocks the update, an empty result is returned (not an error) operationId: queryDatabaseUpdate security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DatabaseUpdateRequest' responses: '200': description: Update successful content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - id: post-uuid title: Updated Title status: published updated_at: '2026-01-13T10:05:00Z' count: 1 '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' /databases/{databaseName}/query/delete: post: tags: - Database Queries summary: Delete data from database (REST API) description: | Delete rows from your database using REST API. **Safety:** Requires at least one filter to prevent accidental mass deletions **Security:** Row-Level Security ensures you can only delete data you have access to **Note:** If RLS blocks the delete, an empty result is returned (not an error) operationId: queryDatabaseDelete security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DatabaseDeleteRequest' responses: '200': description: Delete successful content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - id: post-uuid title: Deleted Post count: 1 '400': description: Invalid request or missing filters content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' /databases/{databaseName}/branches/{branchName}/query/ping: post: tags: - Database Queries summary: Database connectivity probe (REST API) description: | Connectivity probe that runs a fixed `SELECT 1` through pgproxy, using the same authentication, status/bandwidth gating, and metering as the other `/query/*` endpoints. Unlike those endpoints, ping takes **no request body** and performs **no table-name validation**, so it works on any database — including a freshly provisioned, empty one. It is a real committed round-trip through pgproxy, so a `200` means the database is reachable and queryable. Used by the dashboard's database connection test. **Branch-targeted.** Runs against the named branch instead of the parent database, using the branch's own credentials. The branch must be `active` and unexpired. Nothing about this request can reach the parent's data. operationId: queryDatabaseBranchPing security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' responses: '200': description: Database is reachable content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - '?column?': 1 count: 1 '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' '503': $ref: '#/components/responses/DatabaseBranchQueryUnavailable' /databases/{databaseName}/branches/{branchName}/query/select: post: tags: - Database Queries summary: Query database with SELECT (REST API) description: | Query your database using a simple REST API - no SQL required! **Authentication:** Requires auth user access token (from signup/signin) **Row-Level Security:** Automatically enforced - you see only data you have access to **Use Cases:** - Query from browser/mobile apps - Simple data retrieval - Filtered searches with sorting and pagination **Note:** For complex queries (JOINs, CTEs), use Lambda functions with direct SQL **Branch-targeted.** Runs against the named branch instead of the parent database, using the branch's own credentials. The branch must be `active` and unexpired. Nothing about this request can reach the parent's data. operationId: queryDatabaseBranchSelect security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DatabaseSelectRequest' responses: '200': description: Query successful content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - id: uuid-123 title: My Post content: Post content status: published views: 150 created_at: '2026-01-13T10:00:00Z' count: 1 '400': description: Invalid query content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' '503': $ref: '#/components/responses/DatabaseBranchQueryUnavailable' /databases/{databaseName}/branches/{branchName}/query/insert: post: tags: - Database Queries summary: Insert data into database (REST API) description: | Insert new rows into your database using REST API. **Authentication:** Requires auth user access token **Auto-set user_id:** If your table has a trigger using `auth.uid()`, user_id will be automatically set to the authenticated user **Security:** Row-Level Security policies are enforced **Branch-targeted.** Runs against the named branch instead of the parent database, using the branch's own credentials. The branch must be `active` and unexpired. Nothing about this request can reach the parent's data. operationId: queryDatabaseBranchInsert security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DatabaseInsertRequest' responses: '200': description: Insert successful content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - id: uuid-123 title: My New Post content: This is the content status: draft user_id: user-uuid created_at: '2026-01-13T10:00:00Z' count: 1 '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' '503': $ref: '#/components/responses/DatabaseBranchQueryUnavailable' /databases/{databaseName}/branches/{branchName}/query/update: post: tags: - Database Queries summary: Update data in database (REST API) description: | Update existing rows in your database using REST API. **Security:** Row-Level Security ensures you can only update data you have access to **Safety:** Requires at least one filter to prevent accidental mass updates. A request with no `filters` is rejected with `400` (mirrors delete). This matters for service-key queries, which run with full access and bypass RLS. **Note:** If RLS blocks the update, an empty result is returned (not an error) **Branch-targeted.** Runs against the named branch instead of the parent database, using the branch's own credentials. The branch must be `active` and unexpired. Nothing about this request can reach the parent's data. operationId: queryDatabaseBranchUpdate security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DatabaseUpdateRequest' responses: '200': description: Update successful content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - id: post-uuid title: Updated Title status: published updated_at: '2026-01-13T10:05:00Z' count: 1 '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' '503': $ref: '#/components/responses/DatabaseBranchQueryUnavailable' /databases/{databaseName}/branches/{branchName}/query/delete: post: tags: - Database Queries summary: Delete data from database (REST API) description: | Delete rows from your database using REST API. **Safety:** Requires at least one filter to prevent accidental mass deletions **Security:** Row-Level Security ensures you can only delete data you have access to **Note:** If RLS blocks the delete, an empty result is returned (not an error) **Branch-targeted.** Runs against the named branch instead of the parent database, using the branch's own credentials. The branch must be `active` and unexpired. Nothing about this request can reach the parent's data. operationId: queryDatabaseBranchDelete security: - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/DatabaseName' - $ref: '#/components/parameters/BranchName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DatabaseDeleteRequest' responses: '200': description: Delete successful content: application/json: schema: $ref: '#/components/schemas/DatabaseQueryResult' example: data: - id: post-uuid title: Deleted Post count: 1 '400': description: Invalid request or missing filters content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Database or branch not found content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/DatabaseQueryCapExceeded' '503': $ref: '#/components/responses/DatabaseBranchQueryUnavailable' /databases/regions: get: tags: - Databases summary: List platform-supported regions for database provisioning operationId: listDatabaseRegions description: | Returns the regions enabled for database provisioning in this platform environment. These are the same regions offered for function deployment, and the only values the `region` field of a database accepts. This is a public endpoint that doesn't require authentication. responses: '200': description: List of platform-supported regions content: application/json: schema: type: array items: type: object properties: id: type: string example: aws-us-east-1 description: Region identifier for API usage name: type: string example: US East (N. Virginia) description: Human-readable region location /databases/postgres-versions: get: tags: - Databases summary: List available PostgreSQL versions operationId: listPostgresVersions description: | Returns a list of supported PostgreSQL major versions for database provisioning. This is a public endpoint that doesn't require authentication. responses: '200': description: List of available PostgreSQL versions content: application/json: schema: type: array items: type: object properties: version: type: string example: '16' description: PostgreSQL major version number name: type: string example: PostgreSQL 16 description: Human-readable version name default: type: boolean description: Whether this is the default version (recommended) deprecated: type: boolean description: Whether this version is deprecated (approaching EOL) /functions/runtimes: get: tags: - Functions summary: List supported function runtimes operationId: listFunctionRuntimes security: [] description: | Returns the public function runtime catalog used by CLI clients to select supported runtimes, language defaults, and local source packaging metadata for deployments. This is a public endpoint that doesn't require authentication. responses: '200': description: Supported function runtimes content: application/json: schema: $ref: '#/components/schemas/FunctionRuntimesResponse' /functions/regions: get: tags: - Functions summary: List available regions for function deployment operationId: listFunctionRegions security: [] description: | Returns the configured regions where functions can be deployed, each annotated with a human-readable label and country flag emoji for use in UI pickers. This is a public endpoint that doesn't require authentication. responses: '200': description: Available function deployment regions content: application/json: schema: type: array items: $ref: '#/components/schemas/FunctionRegion' /projects/{id}/variables/{name}: get: tags: - Variables summary: Get variable by name description: | Returns a project-level environment variable used by deployed functions and frontends. operationId: getVariable security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/VariableName' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/Variable' '404': description: Variable not found content: application/json: schema: $ref: '#/components/schemas/Error' put: tags: - Variables summary: Update a variable description: | Updates a project-level environment variable and triggers asynchronous propagation to deployed functions and frontends in the project's configured regions. operationId: updateVariable security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/VariableName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateVariableRequest' responses: '200': description: Variable updated content: application/json: schema: $ref: '#/components/schemas/Variable' '404': description: Variable not found content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Private variable membership writes are disabled during rollout content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Variables summary: Delete a variable description: | Deletes a project-level environment variable and triggers asynchronous propagation of the removal to deployed functions and frontends in the project's configured regions. operationId: deleteVariable security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/VariableName' responses: '204': description: Variable deleted '404': description: Variable not found content: application/json: schema: $ref: '#/components/schemas/Error' /auth/password-policy: get: tags: - Authentication summary: Get the effective password policy description: | Returns the backend-enforced password bounds and compromised-password screening status for the project identified by the anon key. A valid anon key is required, but no route-specific auth permission is needed. operationId: authGetPasswordPolicy security: - AnonKey: [] responses: '200': description: Effective password policy content: application/json: schema: $ref: '#/components/schemas/AuthPasswordPolicy' '401': description: Invalid, missing, or revoked anon key content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project or auth configuration not found content: application/json: schema: $ref: '#/components/schemas/Error' /auth/signup: post: tags: - Authentication summary: Sign up a new auth user description: | Create a new end-user account. The project is determined from the anon key. Requires project-specific anon key in Authorization header. **Session-less**: signup never issues a session. On success it returns a uniform acknowledgement (`AuthSignupResponse`) with no tokens; the client obtains a session with a subsequent `POST /auth/signin`. If email confirmation is enabled for the project, a confirmation email is sent and `confirmation_required` is `true`. **Anti-enumeration**: a signup for an already-registered email returns the exact same `201` response as a fresh signup — it never returns `409` — so the response cannot be used to discover which emails are registered. operationId: authSignup security: - AnonKey: [] requestBody: required: true content: application/json: schema: type: object required: - email - password properties: email: type: string format: email password: type: string description: | Password validated after NFC normalization against the policy returned by GET /auth/password-policy. user_metadata: type: object additionalProperties: true responses: '201': description: | Signup acknowledged (session-less). Returned identically for a new account and for an already-registered email (anti-enumeration). content: application/json: schema: $ref: '#/components/schemas/AuthSignupResponse' '400': description: Invalid input (bad email/password format) '401': description: | Unauthorized - Invalid, tampered, revoked, or wrong-project anon key '403': description: | Forbidden - Signups disabled, anon key lacks signup permission, or the email domain is not in `allowed_email_domains`. The internal `anonymous.volcano.internal` domain is reserved for anonymous accounts and is refused whatever the project allows. '429': description: Rate limit exceeded '503': description: Compromised-password screening is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /auth/signin: post: tags: - Authentication summary: Sign in an auth user description: | Authenticate with email and password. Requires an anon key. Set `session_mode` to `cookie` to request HttpOnly refresh-token storage. Cookie mode is honored only for an exact, credentialed CORS origin on the same schemeful site as this API. Otherwise the response retains the refresh token in its body. A frontend on its default Volcano URL is cross-site with this API and so always gets the body token. operationId: authSignin security: - AnonKey: [] requestBody: required: true content: application/json: schema: type: object required: - email - password properties: email: type: string password: type: string session_mode: type: string enum: - cookie responses: '200': description: Signin successful content: application/json: schema: $ref: '#/components/schemas/AuthTokenResponse' '400': description: Invalid input (missing email/password) '401': description: | Unauthorized - Invalid credentials, invalid/tampered/revoked anon key, or account banned/deleted '403': description: | Forbidden - Anon key lacks signin permission, or the email domain is not in `allowed_email_domains` while `allowed_email_domains_mode` is `signup_and_signin`. The domain is taken from the account's canonical email (its primary identity), which is not necessarily the address in the request. '429': description: Rate limit exceeded /auth/refresh: post: tags: - Authentication summary: Refresh access token description: | Get a new access token using a refresh token. Requires an anon key. Send `refresh_token` in the body for the default flow. An eligible cookie-mode browser request may instead send `session_mode: cookie` with an empty token or omit the request body; the API reads and resets the project's HttpOnly cookie and omits `refresh_token` from the response. operationId: authRefresh security: - AnonKey: [] requestBody: required: false content: application/json: schema: type: object properties: refresh_token: type: string session_mode: type: string enum: - cookie responses: '200': description: Token refreshed content: application/json: schema: $ref: '#/components/schemas/AuthTokenResponse' '401': description: Invalid or expired refresh token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | The account's email domain is not in `allowed_email_domains` while `allowed_email_domains_mode` is `signup_and_signin`, so the session cannot be extended content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/Error' /auth/logout: post: tags: - Authentication summary: Logout (revoke refresh token) description: | Invalidate a refresh token. Requires an anon key. Send `refresh_token` for the default flow. An eligible cookie-mode browser request may instead send `session_mode: cookie` with an empty token; logout remains idempotent when the cookie is missing or expired. operationId: authLogout security: - AnonKey: [] requestBody: required: false content: application/json: schema: type: object properties: refresh_token: type: string session_mode: type: string enum: - cookie responses: '204': description: Logged out successfully /auth/forgot-password: post: tags: - Authentication summary: Request password reset description: | Generates recovery token and stores it (email sending pending). Returns generic message to prevent email enumeration. Project is identified via the anon key. operationId: authForgotPassword security: - AnonKey: [] requestBody: required: true content: application/json: schema: type: object required: - email properties: email: type: string format: email responses: '200': description: Generic success message (doesn't reveal if email exists) content: application/json: schema: type: object properties: message: type: string example: If the email exists, a password reset link has been sent '403': description: Password reset is disabled for this project content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Rate limit exceeded (10 requests per hour per IP) content: application/json: schema: $ref: '#/components/schemas/Error' /auth/reset-password: post: tags: - Authentication summary: Reset password with recovery token description: | Reset password using recovery token from forgot-password. Revokes all existing sessions for security. operationId: authResetPassword security: - AnonKey: [] requestBody: required: true content: application/json: schema: type: object required: - token - new_password properties: token: type: string description: Recovery token from forgot-password new_password: type: string description: | Password validated after NFC normalization against the policy returned by GET /auth/password-policy. responses: '200': description: Password reset successful content: application/json: schema: type: object properties: message: type: string '400': description: Password doesn't meet requirements '401': description: Invalid or expired token '503': description: Compromised-password screening is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /auth/confirm: post: tags: - Authentication summary: Confirm email address description: | Confirm email address using token sent via email. Required if require_email_confirmation is enabled. operationId: authConfirmEmail security: - AnonKey: [] requestBody: required: true content: application/json: schema: type: object required: - token properties: token: type: string description: Confirmation token from email responses: '200': description: Email confirmed or already confirmed content: application/json: schema: type: object properties: message: type: string enum: - Email confirmed successfully - Email already confirmed examples: confirmed: summary: Fresh confirmation value: message: Email confirmed successfully alreadyConfirmed: summary: Token belongs to already-confirmed user value: message: Email already confirmed '400': description: Missing confirmation token in request body '401': description: Invalid or expired token /auth/resend-confirmation: post: tags: - Authentication summary: Resend confirmation email description: | Resend email confirmation link. Returns generic message to prevent email enumeration. No email is sent when the account does not exist or is already confirmed. If the account exists and is unconfirmed, a new token is generated and any previous confirmation token is invalidated. operationId: authResendConfirmation security: - AnonKey: [] requestBody: required: true content: application/json: schema: type: object required: - email properties: email: type: string format: email responses: '200': description: Generic success message content: application/json: schema: type: object properties: message: type: string '429': description: Rate limit exceeded content: application/json: schema: $ref: '#/components/schemas/Error' /auth/signup-anonymous: post: tags: - Authentication summary: Create anonymous user description: | Create guest user without email/password. User metadata (like display_name) can be included and will appear in realtime presence events. Requires enable_anonymous_signins to be true. operationId: authSignupAnonymous security: - AnonKey: [] requestBody: description: Optional user metadata content: application/json: schema: type: object properties: user_metadata: type: object additionalProperties: true description: Custom user metadata (e.g., display_name, avatar_url) example: display_name: Alice avatar_url: https://example.com/alice.jpg responses: '201': description: Anonymous user created content: application/json: schema: $ref: '#/components/schemas/AuthTokenResponse' '403': description: Anonymous signins disabled /auth/user/convert-anonymous: post: tags: - Authentication summary: Convert anonymous user to authenticated description: | Add email and password to anonymous user. Requires auth user access token. If require_email_confirmation is enabled for the project, the converted user remains unconfirmed until /auth/confirm succeeds. When email sending is enabled, a confirmation email is sent during conversion. operationId: authConvertAnonymous security: - AuthUserAccessToken: [] requestBody: required: true content: application/json: schema: type: object required: - email - password properties: email: type: string format: email password: type: string description: | Password validated after NFC normalization against the policy returned by GET /auth/password-policy. user_metadata: type: object additionalProperties: true responses: '200': description: User converted successfully content: application/json: schema: type: object properties: user: $ref: '#/components/schemas/AuthUser' '400': description: Not an anonymous user '403': description: | The chosen email domain is not in `allowed_email_domains` '409': description: Email already in use '503': description: Compromised-password screening is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user/change-email: post: tags: - Authentication summary: Request email change description: | Request to change user's email address. Sends confirmation token to new email address. operationId: authRequestEmailChange security: - AuthUserAccessToken: [] requestBody: required: true content: application/json: schema: type: object required: - new_email properties: new_email: type: string format: email responses: '200': description: Confirmation email sent content: application/json: schema: type: object properties: message: type: string new_email: type: string '400': description: Invalid email format or same as current email content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | The requested email domain is not in `allowed_email_domains` content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Email already in use content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Rate limit exceeded (10 requests per hour per IP) content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user/confirm-email-change: post: tags: - Authentication summary: Confirm email change description: Confirm email change with token sent to new address operationId: authConfirmEmailChange security: - AuthUserAccessToken: [] requestBody: required: true content: application/json: schema: type: object required: - email_change_token properties: email_change_token: type: string responses: '200': description: Email changed successfully content: application/json: schema: type: object properties: message: type: string user: $ref: '#/components/schemas/AuthUser' '400': description: Invalid or expired token, or no pending email change content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: | The pending email domain is no longer in `allowed_email_domains`. Re-checked here because the allowlist can narrow between the request and the confirmation. content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Email is now in use by another user content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user/cancel-email-change: delete: tags: - Authentication summary: Cancel pending email change operationId: authCancelEmailChange security: - AuthUserAccessToken: [] responses: '200': description: Email change cancelled content: application/json: schema: type: object properties: message: type: string '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user/sessions: get: tags: - Authentication summary: Get current user's sessions description: | Returns paginated sessions for the currently authenticated user. Each session includes device info, IP addresses, and activity timestamps. The current session is marked with `is_current: true`. **Ordering and pagination.** Without `sort`, results are ordered by most recent activity and paged with `page`/`limit`, returning the `sessions`/`total`/`page`/`limit`/`total_pages` body below. This is the legacy default and is preserved for existing clients. Send `sort=created_at` to opt into the standard list contract: results are ordered by session start (newest first) and may be paged either with `page`/`limit` or by cursor with `cursor`/`ending_before` plus a bounded `offset` past the cursor anchor. Cursor responses use the shared `data` envelope with `next_cursor`/`prev_cursor`. Unlike other list endpoints, sending `limit` without `page` does **not** select cursor mode here; `sort=created_at` is the only opt-in. Cursor pagination is rejected with 400 for the activity order, because `last_activity_at` changes whenever a session refreshes its token: a row that crosses the cursor anchor between two requests would be skipped and never shown. The `status=expired` filter is also offset-only because a session can expire above the cursor anchor during a walk. Sending that filter in cursor mode, `page` with `cursor` or `ending_before`, or both cursor directions returns 400. operationId: authGetMySessions security: - AuthUserAccessToken: [] parameters: - name: page in: query description: Page number (1-indexed) schema: type: integer minimum: 1 default: 1 - name: limit in: query description: Number of sessions per page (max 100) schema: type: integer minimum: 1 maximum: 100 default: 20 - name: sort in: query description: | Sort key. `last_activity` (default) orders by most recent activity and supports offset pagination only. `created_at` orders by session start and supports both offset and cursor pagination. schema: type: string enum: - last_activity - created_at default: last_activity - name: status in: query description: | Filter by whether the session can still be refreshed. Omit for every stored session, including expired ones. `expired` is not supported with cursor pagination. schema: type: string enum: - active - expired - name: cursor in: query description: | Opaque keyset cursor from a previous response's `next_cursor`. Requires `sort=created_at`; mutually exclusive with `page` and `ending_before`. schema: type: string - name: ending_before in: query description: | Opaque keyset cursor from a previous response's `prev_cursor`, paging backward. Requires `sort=created_at`; mutually exclusive with `page` and `cursor`. schema: type: string - name: offset in: query description: | Bounded number of rows to skip past the cursor anchor (the hybrid jump, maximum 100000). Ignored unless `cursor` or `ending_before` is supplied. schema: type: integer minimum: 0 maximum: 100000 responses: '200': description: Paginated list of user sessions content: application/json: schema: type: object properties: sessions: type: array items: $ref: '#/components/schemas/AuthSession' total: type: integer description: Total number of sessions page: type: integer description: Current page number limit: type: integer description: Number of sessions per page total_pages: type: integer description: Total number of pages data: type: array description: Sessions for this page (cursor pagination only) items: $ref: '#/components/schemas/AuthSession' has_more: type: boolean description: Whether a further page exists (cursor pagination only) next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. '400': description: Invalid or conflicting pagination parameters content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Authentication summary: Sign out from all other devices description: | Deletes all sessions except the current one. Use this to log out from all other devices while keeping the current session active. operationId: authDeleteAllMySessions security: - AuthUserAccessToken: [] responses: '204': description: All other sessions deleted '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user/sessions/{sessionId}: delete: tags: - Authentication summary: Sign out from specific device description: | Deletes a specific session, logging out that device. You can get session IDs from the list sessions endpoint. operationId: authDeleteMySession security: - AuthUserAccessToken: [] parameters: - name: sessionId in: path required: true description: The session ID to delete schema: type: string format: uuid responses: '204': description: Session deleted '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Session not found content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user: get: tags: - Authentication summary: Get current user profile description: Returns authenticated user's profile. Requires access token. operationId: authGetUser security: - AuthUserAccessToken: [] responses: '200': description: User profile content: application/json: schema: type: object properties: user: $ref: '#/components/schemas/AuthUser' '401': description: Not authenticated - access token missing or invalid content: application/json: schema: $ref: '#/components/schemas/Error' put: tags: - Authentication summary: Update user profile description: Update password or metadata. Requires access token. operationId: authUpdateUser security: - AuthUserAccessToken: [] requestBody: content: application/json: schema: type: object properties: password: type: string description: | Password validated after NFC normalization against the policy returned by GET /auth/password-policy. user_metadata: type: object additionalProperties: true description: | Metadata keys to merge into the current user metadata. Omitted keys remain unchanged; set a key to null to remove it. Merging is shallow; nested objects replace the stored value for that top-level key. responses: '200': description: Profile updated content: application/json: schema: type: object properties: user: $ref: '#/components/schemas/AuthUser' '400': description: Bad request - invalid password or metadata format content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated - access token missing or invalid content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Compromised-password screening is temporarily unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user/identities: get: tags: - Authentication summary: List the current user's identities description: | Returns every real email identity the account owns. An account can own multiple identities (for example a password identity plus one or more OAuth identities on different emails). Anonymous accounts have no real identity and return an empty list. operationId: authListIdentities security: - AuthUserAccessToken: [] responses: '200': description: List of identities content: application/json: schema: $ref: '#/components/schemas/AuthIdentitiesResponse' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user/identities/{identityId}: delete: tags: - Authentication summary: Unlink an identity from the current user description: | Removes a non-primary identity and its attached sign-in methods. Refused when the identity is the account's primary, its only identity, or when removing it would leave the account with no way to sign in. operationId: authUnlinkIdentity security: - AuthUserAccessToken: [] parameters: - name: identityId in: path required: true description: The identity ID to unlink schema: type: string format: uuid responses: '204': description: Identity unlinked '400': description: Identity cannot be unlinked (primary, last, or would remove last sign-in method), or the identity id is malformed content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Identity not found content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user/methods: get: tags: - Authentication summary: List the current user's sign-in methods description: | Returns a flat list of every sign-in method the account owns (password, each OAuth provider, and any active anonymous method), with the primary method flagged. Password stubs and converted anonymous methods are excluded. operationId: authListMethods security: - AuthUserAccessToken: [] responses: '200': description: List of sign-in methods content: application/json: schema: $ref: '#/components/schemas/AuthMethodsResponse' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' /auth/user/methods/{methodId}/promote: post: tags: - Authentication summary: Set a method as the account's primary description: | Promotes the given method to the account's primary sign-in method. The account's canonical email is re-derived from the promoted method's identity. Refused for password stubs and converted anonymous methods, and for an identity whose domain is outside the project's `allowed_email_domains`. operationId: authPromoteMethod security: - AuthUserAccessToken: [] parameters: - name: methodId in: path required: true description: The method ID to promote schema: type: string format: uuid responses: '200': description: The promoted method content: application/json: schema: $ref: '#/components/schemas/AuthMethodSummary' '400': description: This method cannot be set as primary (password stub, converted anonymous method, or unverified email), or the method id is malformed content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: The promoted identity's email domain is not in the project's allowed_email_domains content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Method not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/auth/insights: get: tags: - Auth Admin summary: Get auth user insights description: | Returns current auth-user totals, rolling 30-day active users, and zero-filled signup and successful sign-in counts for an inclusive UTC date range. Weeks start on Monday. Sign-in counts and active-user activity begin when collection is deployed. Historical signup counts are backfilled from users present at deployment. Token refreshes affect active users but not the sign-in series. operationId: getAuthInsights security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: from in: query description: Inclusive UTC start date. Defaults to 29 days before `to`. schema: type: string format: date - name: to in: query description: Inclusive UTC end date. Defaults to today. schema: type: string format: date - name: interval in: query description: Chart bucket size. Defaults to `day`. schema: $ref: '#/components/schemas/AuthInsightsInterval' responses: '200': description: Auth insights retrieved content: application/json: schema: $ref: '#/components/schemas/AuthInsightsResponse' example: project_id: 4f165080-a931-4e03-b3bd-41c45c3f0058 observed_at: '2026-07-20T18:00:00Z' window: from: '2026-06-21' to: '2026-07-20' interval: day summary: total_users: 1234 active_users_30d: 418 series: - bucket_start: '2026-07-20' signups: 12 signins: 97 is_partial: true '400': description: Invalid date range or interval content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized - invalid or missing token content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/auth/users: get: tags: - Auth Admin summary: List all auth users (admin) description: List auth users in project. Requires platform token. operationId: listAuthUsers security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' - name: status in: query required: false description: Filter by effective status. `banned` returns only currently-banned users; an expired temporary ban lists as `active`. schema: type: string enum: - active - banned responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/PaginatedAuthUsers' '400': description: Invalid status or pagination parameters content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/auth/users/{userId}: get: tags: - Auth Admin summary: Get specific auth user (admin) operationId: getAuthUser security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: userId in: path required: true schema: type: string format: uuid responses: '200': description: Auth user details content: application/json: schema: $ref: '#/components/schemas/AuthUser' delete: tags: - Auth Admin summary: Delete auth user (admin) description: Soft-deletes user and revokes all sessions operationId: deleteAuthUser security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: userId in: path required: true schema: type: string format: uuid responses: '204': description: User deleted /projects/{id}/auth/users/{userId}/sessions: get: tags: - Auth Admin summary: List user sessions description: | List paginated sessions for a specific auth user. Returns session details including device info, IP address, and activity timestamps. Ordering and pagination match `GET /auth/user/sessions`: the default is activity order with `page`/`limit` and the legacy `sessions` body, and `sort=created_at` opts into the standard cursor/offset hybrid with the shared `data` envelope. Cursor pagination is only available for `sort=created_at`, because the activity timestamp changes under paging. The `status=expired` filter is offset-only because sessions can expire above a cursor anchor during a walk. operationId: listUserSessions security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: userId in: path required: true schema: type: string format: uuid - name: page in: query description: Page number (1-indexed) schema: type: integer minimum: 1 default: 1 - name: limit in: query description: Number of sessions per page (max 100) schema: type: integer minimum: 1 maximum: 100 default: 20 - name: sort in: query description: | Sort key. `last_activity` (default) orders by most recent activity and supports offset pagination only. `created_at` orders by session start and supports both offset and cursor pagination. schema: type: string enum: - last_activity - created_at default: last_activity - name: status in: query description: | Filter by whether the session can still be refreshed. Omit for every stored session, including expired ones. `expired` is not supported with cursor pagination. schema: type: string enum: - active - expired - name: cursor in: query description: | Opaque keyset cursor from a previous response's `next_cursor`. Requires `sort=created_at`; mutually exclusive with `page` and `ending_before`. schema: type: string - name: ending_before in: query description: | Opaque keyset cursor from a previous response's `prev_cursor`, paging backward. Requires `sort=created_at`; mutually exclusive with `page` and `cursor`. schema: type: string - name: offset in: query description: | Bounded number of rows to skip past the cursor anchor (the hybrid jump, maximum 100000). Ignored unless `cursor` or `ending_before` is supplied. schema: type: integer minimum: 0 maximum: 100000 responses: '200': description: Paginated list of user sessions content: application/json: schema: type: object properties: sessions: type: array items: $ref: '#/components/schemas/AuthSession' total: type: integer description: Total number of sessions page: type: integer description: Current page number limit: type: integer description: Number of sessions per page total_pages: type: integer description: Total number of pages data: type: array description: Sessions for this page (cursor pagination only) items: $ref: '#/components/schemas/AuthSession' has_more: type: boolean description: Whether a further page exists (cursor pagination only) next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. '400': description: Invalid or conflicting pagination parameters content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: User not found delete: tags: - Auth Admin summary: Delete all user sessions description: | Revokes all sessions for a user, forcing them to re-authenticate on all devices. Use this to log out a user from everywhere. operationId: deleteAllUserSessions security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: userId in: path required: true schema: type: string format: uuid responses: '204': description: All sessions deleted '404': description: User not found /projects/{id}/auth/users/{userId}/sessions/{sessionId}: delete: tags: - Auth Admin summary: Delete specific session description: | Revokes a specific session for a user. Use this to log out a user from a single device. operationId: deleteUserSession security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: userId in: path required: true schema: type: string format: uuid - name: sessionId in: path required: true schema: type: string format: uuid responses: '204': description: Session deleted '404': description: Session or user not found /projects/{id}/auth/users/{userId}/ban: post: tags: - Auth Admin summary: Ban a user description: | Bans a user temporarily or permanently. Banned users cannot sign in and all their active sessions are immediately revoked. - Omit `banned_until` for a permanent ban - Provide `banned_until` ISO timestamp for a temporary ban operationId: banAuthUser security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: userId in: path required: true schema: type: string format: uuid requestBody: content: application/json: schema: type: object properties: banned_until: type: string format: date-time description: When the ban expires (omit for permanent ban) example: '2026-12-31T23:59:59Z' responses: '200': description: User banned successfully content: application/json: schema: $ref: '#/components/schemas/BanUserResponse' '404': description: User not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/auth/users/{userId}/unban: post: tags: - Auth Admin summary: Unban a user description: | Removes a ban from a user, restoring their ability to sign in. The user's status is set back to 'active'. operationId: unbanAuthUser security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: userId in: path required: true schema: type: string format: uuid responses: '200': description: User unbanned successfully content: application/json: schema: $ref: '#/components/schemas/UnbanUserResponse' '404': description: User not found content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/email-templates: get: tags: - Auth Configuration summary: List email templates description: Returns all custom email templates for this project. operationId: listEmailTemplates security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Email templates list content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/EmailTemplate' post: tags: - Auth Configuration summary: Create email template description: | Creates a custom email template for the project. Custom email templates are a SUPERAGENT-plan feature: requests from a HOBBY-plan project owner are rejected with 403, and HOBBY projects always send the built-in default templates regardless of any previously saved custom rows. Every project is created with one template per type, so customizing one is usually a PUT; creating a type the project already has returns 409. Valid template types: welcome, confirmation, password_reset, password_changed operationId: createEmailTemplate security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateEmailTemplateRequest' responses: '201': description: Template created content: application/json: schema: $ref: '#/components/schemas/EmailTemplate' '400': description: Invalid template type content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Custom email templates require the SUPERAGENT plan content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: The project already has a template of this type content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/email-templates/{type}: get: tags: - Auth Configuration summary: Get email template operationId: getEmailTemplate security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: type in: path required: true schema: type: string enum: - welcome - confirmation - password_reset - password_changed responses: '200': description: Email template content: application/json: schema: $ref: '#/components/schemas/EmailTemplate' '404': description: Template not found put: tags: - Auth Configuration summary: Update email template description: | Updates a custom email template. Custom email templates are a SUPERAGENT-plan feature: requests from a HOBBY-plan project owner are rejected with 403 (including after a SUPERAGENT→HOBBY downgrade), so a HOBBY project cannot modify templates and always sends the built-in defaults. operationId: updateEmailTemplate security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: type in: path required: true schema: type: string enum: - welcome - confirmation - password_reset - password_changed requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateEmailTemplateRequest' responses: '200': description: Template updated content: application/json: schema: $ref: '#/components/schemas/EmailTemplate' '403': description: Custom email templates require the SUPERAGENT plan content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Template not found delete: tags: - Auth Configuration summary: Delete email template description: | Deletes a custom template, reverting to the default. Custom email templates are a SUPERAGENT-plan feature: requests from a HOBBY-plan project owner are rejected with 403. operationId: deleteEmailTemplate security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: type in: path required: true schema: type: string enum: - welcome - confirmation - password_reset - password_changed responses: '204': description: Template deleted '403': description: Custom email templates require the SUPERAGENT plan content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Template not found /email-templates/defaults: get: tags: - Auth Configuration summary: Get default email templates description: Returns the default email templates used when no custom template is configured. operationId: getDefaultEmailTemplates responses: '200': description: Default templates content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/EmailTemplate' /email-templates/defaults/{type}: get: tags: - Auth Configuration summary: Get default email template by type operationId: getDefaultEmailTemplate parameters: - name: type in: path required: true schema: type: string enum: - welcome - confirmation - password_reset - password_changed responses: '200': description: Default template content: application/json: schema: $ref: '#/components/schemas/EmailTemplate' '404': description: Template type not found /projects/{id}/auth/config: get: tags: - Auth Configuration summary: Get auth configuration operationId: getAuthConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Auth configuration content: application/json: schema: $ref: '#/components/schemas/AuthConfig' put: tags: - Auth Configuration summary: Update auth configuration description: | Updates the project's auth configuration. Only the fields present in the body are changed. operationId: updateAuthConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateAuthConfigRequest' responses: '200': description: Configuration updated content: application/json: schema: $ref: '#/components/schemas/AuthConfig' '403': description: | The update would turn on, widen, or otherwise edit the email domain allowlist (`allowed_email_domains`, `allowed_email_domains_mode`) for a project that is not on the SUPERAGENT plan. A HOBBY project keeps whatever allowlist it already has — parked, enforcing nothing until it upgrades — and may still remove it, so a downgrade never leaves a project locked out of its own signups. content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/auth/config/test-email: post: tags: - Auth Configuration summary: Send a test email using the project's saved SMTP config description: | Sends a diagnostic email to `to_email` using the project's persisted `auth_config` SMTP credentials. If `html_body` or `text_body` is supplied, the override path is taken: those values (plus optional `subject`) are rendered through html/text templates against the project's `Data` and used as the body — used by the template editor's "Send Test" affordance to preview an unsaved template. With both bodies omitted, a hardcoded diagnostic message is sent and any `subject` field is ignored. Sending `subject` alone (no bodies) is rejected with 400 to avoid a silently-dropped subject or a blank message. Also rejects with 400 if `email_enabled=false` or `smtp_host` is empty. operationId: testEmailConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TestEmailRequest' responses: '200': description: Test email sent content: application/json: schema: $ref: '#/components/schemas/TestEmailResponse' '400': description: Invalid request or email delivery not configured '401': description: Unauthorized '403': description: Forbidden '404': description: Project not found '502': description: Template render failure or SMTP delivery failed /projects/{id}/auth/hosted-pages/{pageType}: get: tags: - Auth Configuration summary: Get hosted auth page description: | Returns the saved HTML/CSS for the page type, or `page: null` when the project has not customized it yet. Always returns `defaults` (the theme shell to seed an editor with, which is valid input to the update endpoint) and `runtime` (the script the rendered page runs, plus a preview harness). operationId: getAuthHostedPage security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: pageType in: path required: true schema: $ref: '#/components/schemas/HostedAuthPageType' responses: '200': description: Hosted page loaded content: application/json: schema: $ref: '#/components/schemas/AuthHostedPageResponse' put: tags: - Auth Configuration summary: Update hosted auth page description: | Saves the current HTML/CSS for this page type. Security validation rejects script tags, javascript: URLs, inline event handlers, iframe/object/embed/meta/link tags in HTML, and closing style/head tags in CSS. operationId: updateAuthHostedPage security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: pageType in: path required: true schema: $ref: '#/components/schemas/HostedAuthPageType' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateAuthHostedPageRequest' responses: '200': description: Hosted page updated content: application/json: schema: $ref: '#/components/schemas/AuthHostedPageResponse' '400': description: Invalid input or unsafe markup '401': description: Unauthorized '403': description: Forbidden '404': description: Project not found /projects/{id}/auth/pages/appearance: get: tags: - Auth Configuration summary: Get managed auth page appearance operationId: getAuthPageAppearance security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Saved appearance and effective plan state content: application/json: schema: $ref: '#/components/schemas/AuthPageAppearanceResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Appearance could not be read content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/auth/pages/theme: put: tags: - Auth Configuration summary: Save the managed auth page theme operationId: updateAuthPageTheme security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateAuthPageThemeRequest' responses: '200': description: Theme saved content: application/json: schema: $ref: '#/components/schemas/UpdateAuthPageThemeRequest' '400': description: Invalid or unreadable theme content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Plan does not permit customisation content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Theme could not be saved content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Auth Configuration summary: Clear the managed auth page theme operationId: deleteAuthPageTheme security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '204': description: Theme cleared '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Plan does not permit customisation content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Theme could not be cleared content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/auth/pages/{pageType}/layout: parameters: - $ref: '#/components/parameters/ProjectId' - name: pageType in: path required: true schema: $ref: '#/components/schemas/HostedAuthPageType' put: tags: - Auth Configuration summary: Save one managed auth page layout operationId: updateAuthPageLayout security: - UserToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateAuthPageLayoutRequest' responses: '200': description: Layout saved content: application/json: schema: $ref: '#/components/schemas/UpdateAuthPageLayoutRequest' '400': description: Invalid page type or layout content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Plan does not permit customisation content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Layout could not be saved content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Auth Configuration summary: Clear one managed auth page layout operationId: deleteAuthPageLayout security: - UserToken: [] responses: '204': description: Layout cleared '400': description: Invalid page type content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Plan does not permit customisation content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Layout could not be cleared content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/auth/pages/{pageType}/preview: get: tags: - Auth Configuration summary: Render a short-lived managed auth page preview description: | Public HTML endpoint for a preview URL returned by the POST operation. The signed ticket contains the unsaved appearance, expires shortly, and runs the production page runtime against mocked authentication responses. operationId: renderAuthPagePreview security: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: pageType in: path required: true schema: $ref: '#/components/schemas/HostedAuthPageType' - name: ticket in: query required: true schema: type: string minLength: 1 maxLength: 4096 description: Short-lived signed preview ticket returned by the POST operation. responses: '200': description: Rendered preview document content: text/html: schema: type: string '404': description: Ticket is invalid or expired, its path does not match, or managed authentication is disabled content: text/plain: schema: type: string '500': description: Preview could not be rendered content: text/plain: schema: type: string post: tags: - Auth Configuration summary: Preview an unsaved managed auth page appearance operationId: previewAuthPage security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: pageType in: path required: true schema: $ref: '#/components/schemas/HostedAuthPageType' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PreviewAuthPageRequest' responses: '200': description: Short-lived URL for the rendered preview document content: application/json: schema: $ref: '#/components/schemas/PreviewAuthPageResponse' '400': description: Invalid page type or draft content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found or managed authentication is disabled content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Preview could not be rendered content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/auth/hosted/{pageType}: get: tags: - Auth Configuration summary: Render a managed auth page description: | Public HTML endpoint for signup, forgot-password, device approval, verify-email, and reset-password pages. Login uses the path without a page type. Requires `Accept: text/html`. Returns 404 when managed hosted pages are disabled for the project. security: [] operationId: renderManagedAuthPage parameters: - $ref: '#/components/parameters/ProjectId' - name: pageType in: path required: true schema: $ref: '#/components/schemas/HostedRenderablePageType' responses: '200': description: Hosted auth page HTML content: text/html: schema: type: string '400': description: Invalid project id or unsupported Accept header '404': description: Managed pages disabled or page type not found /projects/{id}/auth/hosted: get: tags: - Auth Configuration summary: Render default managed auth page description: | Public HTML endpoint for the managed login page. Requires `Accept: text/html`. security: [] operationId: renderDefaultManagedAuthPage parameters: - $ref: '#/components/parameters/ProjectId' - name: action in: query required: false schema: type: string enum: - login - signup - forgot-password - device description: | Optional deep-link action for the unified hosted page. Ignored when a custom login page is configured. `action=device` renders the device authorization approval UI inline (no redirect to any external app); it signs the user in and calls `POST /auth/device/verify`. - name: user_code in: query required: false schema: type: string description: Device user code (from `POST /auth/device/authorize`) used with `action=device`. - name: anon_key in: query required: false schema: type: string description: Project anon key used by built-in managed auth flows (required for login/signup/device actions). - name: state in: query required: false schema: type: string description: | Opaque one-time nonce generated by the client SDK before redirecting here. On successful login/signup it is echoed back in the post-auth redirect fragment as `state`, so the SDK can bind the returned session to the flow it initiated (login-CSRF / session-fixation defense). The SDK rejects a returned session whose `state` does not match. responses: '200': description: Hosted auth page HTML content: text/html: schema: type: string '400': description: Invalid project id or unsupported Accept header '404': description: Managed pages disabled /projects/{id}/auth/hosted/login/options: get: tags: - Auth Configuration summary: Get hosted login runtime options description: | Returns runtime options for the built-in managed login flow. Requires `anon_key` query parameter. Rate limited per project and client IP. Excess requests return `429` and `Retry-After`. security: [] operationId: getHostedLoginOptions parameters: - $ref: '#/components/parameters/ProjectId' - name: anon_key in: query required: true schema: type: string responses: '200': description: Hosted login options returned content: application/json: schema: $ref: '#/components/schemas/HostedLoginOptionsResponse' '401': description: Invalid or missing anon key '404': description: Managed pages disabled '429': description: Rate limit exceeded /projects/{id}/auth/hosted/login/check-email: post: tags: - Auth Configuration summary: Check whether email exists for hosted login flow description: | Used by the built-in managed login page to branch UI between signin and signup. Requires anon key in Authorization header. Rate limited per project and client IP. Excess requests return `429` and `Retry-After`. security: [] operationId: hostedLoginCheckEmail parameters: - $ref: '#/components/parameters/ProjectId' - name: Authorization in: header required: true schema: type: string description: Bearer anon key (`Bearer `) requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/HostedLoginEmailCheckRequest' responses: '200': description: Email existence evaluated content: application/json: schema: $ref: '#/components/schemas/HostedLoginEmailCheckResponse' '401': description: Invalid or missing anon key '429': description: Rate limit exceeded /projects/{id}/auth/methods: get: tags: - Auth Configuration summary: Get all authentication methods description: | Returns all configured authentication methods for this project, including email/password, anonymous, device authorization, and OAuth providers. operationId: getAuthMethods security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Authentication methods configuration content: application/json: schema: type: object properties: email_password: type: object properties: enabled: type: boolean method: type: string name: type: string anonymous: type: object properties: enabled: type: boolean method: type: string name: type: string oauth_providers: type: array items: type: object properties: enabled: type: boolean method: type: string provider: type: string name: type: string redirect_url: type: string scopes: type: array items: type: string available_methods: type: array items: type: string example: - email_password - oauth_google - oauth_github put: tags: - Auth Configuration summary: Configure authentication methods (unified) description: | Configure all authentication methods in a single request. At least one method must remain enabled. operationId: configureAuthMethods security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: content: application/json: schema: type: object properties: enable_email_password: type: boolean enable_anonymous: type: boolean oauth_providers: type: array items: type: object properties: provider: type: string enabled: type: boolean responses: '200': description: Methods configured '400': description: At least one method must be enabled /projects/{id}/oauth/configs: get: tags: - OAuth Configuration summary: List OAuth configurations description: List all OAuth provider configurations for this project operationId: listOAuthConfigs security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: List of OAuth configurations content: application/json: schema: type: object properties: configs: type: array items: $ref: '#/components/schemas/OAuthConfig' post: tags: - OAuth Configuration summary: Create OAuth configuration description: Configure OAuth provider (Google, GitHub, Microsoft, Apple, Device) operationId: createOAuthConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateOAuthConfigRequest' responses: '201': description: OAuth config created content: application/json: schema: $ref: '#/components/schemas/OAuthConfig' '409': description: Provider already configured /projects/{id}/oauth/configs/{provider}: get: tags: - OAuth Configuration summary: Get OAuth configuration operationId: getOAuthConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple - device - name: client_id in: query required: false schema: type: string description: Required when `provider=device` to select a specific device client. responses: '200': description: OAuth configuration content: application/json: schema: $ref: '#/components/schemas/OAuthConfig' put: tags: - OAuth Configuration summary: Update OAuth configuration operationId: updateOAuthConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple - device - name: client_id in: query required: false schema: type: string description: Required when `provider=device` to select a specific device client. requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateOAuthConfigRequest' responses: '200': description: OAuth config updated content: application/json: schema: $ref: '#/components/schemas/OAuthConfig' delete: tags: - OAuth Configuration summary: Delete OAuth configuration operationId: deleteOAuthConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple - device - name: client_id in: query required: false schema: type: string description: Required when `provider=device` to select a specific device client. responses: '204': description: OAuth config deleted /projects/{id}/oauth/providers: get: tags: - OAuth Configuration summary: List available OAuth providers description: Get list of supported OAuth providers and their default scopes operationId: listAvailableOAuthProviders security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Available providers content: application/json: schema: type: object properties: providers: type: array items: type: object properties: id: type: string name: type: string default_scopes: type: array items: type: string /auth/oauth/{provider}/authorize: get: tags: - OAuth Authentication summary: Start OAuth authorization description: | Redirects user to OAuth provider for authorization. Handles CSRF protection with state parameter. Project is identified via the anon_key query parameter. operationId: authOAuthAuthorize parameters: - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple - name: anon_key in: query required: true schema: type: string description: Project anon key (required - identifies the project) - name: redirect_url in: query schema: type: string description: | URL to redirect to after the OAuth flow (optional). Must exactly match an entry in the project's `allowed_redirect_urls`, including its query string, or be the project's own managed hosted-auth page URL. - name: client_state in: query schema: type: string maxLength: 255 description: | Optional application nonce. It is stored with the server-generated provider state and echoed to redirect_url as `state`. - name: response_mode in: query schema: type: string enum: - code description: | Set to `code` to receive a short-lived authorization code at redirect_url, then use POST /auth/oauth/exchange to obtain the session. `redirect_url` is required in this mode. When omitted, the established session-fragment response is retained for compatibility with existing clients. responses: '307': description: Redirect to OAuth provider '400': description: | OAuth provider is disabled for this project, or `redirect_url` is not registered in `allowed_redirect_urls` '404': description: OAuth provider not configured /auth/oauth/{provider}/callback: get: tags: - OAuth Authentication summary: OAuth callback handler description: | Handles OAuth provider callback with authorization code. Exchanges code for tokens and creates/signs in user. operationId: authOAuthCallback parameters: - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple - name: code in: query required: true schema: type: string - name: state in: query required: true schema: type: string - name: error in: query schema: type: string responses: '200': description: Existing user signed in (when redirect_url was omitted) content: application/json: schema: $ref: '#/components/schemas/AuthTokenResponse' '201': description: New user created and signed in (when redirect_url was omitted) content: application/json: schema: $ref: '#/components/schemas/AuthTokenResponse' '303': description: | Redirect to the exact registered redirect_url. Flows that requested response_mode=code receive a short-lived, single-use `code` and optional application `state`; compatibility flows receive the established session fragment. '400': description: | Missing/invalid code or state, the state parameter expired, or the flow's stored redirect_url is no longer registered in allowed_redirect_urls (re-checked at callback time) '403': description: | The provider's email domain is not in `allowed_email_domains`. Creating an account is refused under `signup` and `signup_and_signin`; signing in an already-linked account is refused under `signup_and_signin`. '409': description: Email already exists (requires linking) /auth/oauth/exchange: post: tags: - OAuth Authentication summary: Exchange OAuth authorization code description: | Atomically consumes a short-lived callback code and returns the user's session. The request must use the same project anon key and exact redirect_url that initiated the flow. operationId: authOAuthExchange security: - AnonKey: [] requestBody: required: true content: application/json: schema: type: object required: - code - redirect_url properties: code: type: string redirect_url: type: string format: uri responses: '200': description: Authorization code consumed and session created content: application/json: schema: $ref: '#/components/schemas/AuthTokenResponse' '400': description: Invalid, expired, consumed, or redirect-mismatched code '401': description: Missing or invalid project anon key '403': description: | Email confirmation is now required, or the account's email domain is not in `allowed_email_domains` while `allowed_email_domains_mode` is `signup_and_signin`. Both are re-checked here because the code outlives the callback that issued it. '429': description: Too many exchange attempts from this client /auth/device/authorize: post: tags: - OAuth Authentication summary: Start RFC8628 device authorization description: | Starts OAuth 2.0 Device Authorization Grant (RFC 8628). Returns `device_code` for the CLI and `user_code` for browser verification. By default the returned `verification_uri` / `verification_uri_complete` point at the project's managed device-approval page served by this API (`/projects/{projectId}/auth/hosted?action=device&user_code=...&anon_key=...`), which requires managed auth enabled and a default anon key for the project. Projects can override this by setting `device_verification_url` on the auth config (`PATCH /auth/config`). When set, that URL is returned as-is with the `user_code` appended (no `action=device` hint and no embedded anon key — the page brings its own), so a CLI's `login` command surfaces the project's own RFC 8628 approval page. With a custom URL, device login does **not** require managed auth to be enabled; the custom page's origin must be in the project's auth CORS allowlist to call `POST /auth/device/verify`. Either way the verification page must authenticate the end user and call `POST /auth/device/verify` with the `user_code`. See the device-auth guide for both approaches. operationId: authDeviceAuthorize requestBody: required: true content: application/json: schema: type: object required: - client_id properties: client_id: type: string description: Enabled `device` OAuth client ID for the target project responses: '200': description: Device authorization started content: application/json: schema: $ref: '#/components/schemas/DeviceAuthorizationResponse' '400': description: Invalid request or unauthorized client content: application/json: schema: $ref: '#/components/schemas/OAuthErrorResponse' /auth/device/token: post: tags: - OAuth Authentication summary: Poll device token endpoint description: | RFC8628 token polling endpoint. Returns OAuth errors such as `authorization_pending`, `slow_down`, `access_denied`, and `expired_token`. operationId: authDeviceToken requestBody: required: true content: application/json: schema: type: object required: - grant_type - device_code - client_id properties: grant_type: type: string enum: - urn:ietf:params:oauth:grant-type:device_code device_code: type: string client_id: type: string responses: '200': description: Device flow completed, auth-user session minted content: application/json: schema: $ref: '#/components/schemas/AuthTokenResponse' '400': description: Polling state/error response content: application/json: schema: $ref: '#/components/schemas/OAuthErrorResponse' '403': description: | `access_denied` - the approving account's email domain is not in `allowed_email_domains` while `allowed_email_domains_mode` is `signup_and_signin`. Re-checked here because approval and redemption are separate requests. content: application/json: schema: $ref: '#/components/schemas/OAuthErrorResponse' /auth/device/verify: post: tags: - OAuth Authentication summary: Approve or deny a device code description: | Browser-side endpoint for authenticated auth-users to approve (`approve`) or deny (`deny`) a `user_code`. Called by the verification page after the end user signs in. The grant is scoped to the project the auth-user token belongs to: approving a `user_code` issued for a different project returns `403`. This endpoint does not require managed auth to be enabled, so a custom verification page (hosted anywhere) can drive approval — it just needs an authenticated project auth-user access token and, for cross-origin browser calls, the page origin allowed in the project's auth CORS settings. operationId: authDeviceVerify security: - AuthUserAccessToken: [] requestBody: required: true content: application/json: schema: type: object required: - user_code properties: user_code: type: string action: type: string enum: - approve - deny default: approve responses: '200': description: Verification action accepted content: application/json: schema: type: object properties: success: type: boolean status: type: string '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' /auth/platform/exchange: post: tags: - OAuth Authentication summary: Exchange auth-user device session for platform token description: | Exchanges a verified auth-user device-flow session into a platform token for CLI usage. The target platform user is derived from authenticated auth-user mapping; client cannot select another user. operationId: authPlatformExchange security: - AuthUserAccessToken: [] requestBody: required: true content: application/json: schema: type: object required: - client_id properties: client_id: type: string responses: '200': description: Platform token minted content: application/json: schema: $ref: '#/components/schemas/PlatformExchangeResponse' '403': description: | Exchange not allowed for this session/client/project, or the account's email domain is not in `allowed_email_domains` while `allowed_email_domains_mode` is `signup_and_signin`. The domain is re-checked here because the minted platform token outlives the session it is exchanged from. content: application/json: schema: $ref: '#/components/schemas/Error' /auth/oauth/providers: get: tags: - OAuth Authentication summary: List user's linked providers description: Get list of OAuth providers linked to current user operationId: authListOAuthProviders security: - AuthUserAccessToken: [] responses: '200': description: Linked providers content: application/json: schema: type: object properties: providers: type: array items: type: object properties: provider: type: string linked_at: type: string format: date-time updated_at: type: string format: date-time '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' /auth/oauth/{provider}/link: post: tags: - OAuth Authentication summary: Link OAuth provider to current user description: | Generates authorization URL to link OAuth provider to existing account. User must be authenticated. operationId: authLinkOAuthProvider security: - AuthUserAccessToken: [] parameters: - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple - name: redirect_url in: query schema: type: string description: | URL to redirect to after linking completes (optional). Same allowed_redirect_urls requirement as GET /auth/oauth/{provider}/authorize. - name: client_state in: query schema: type: string maxLength: 255 description: | Optional application nonce echoed to redirect_url as `state`. - name: response_mode in: query schema: type: string enum: - code description: | Set to `code` to receive a short-lived authorization code at redirect_url. `redirect_url` is required in this mode. When omitted, the established session-fragment response is retained for compatibility with existing clients. responses: '200': description: Authorization URL generated content: application/json: schema: type: object properties: authorization_url: type: string '400': description: redirect_url is not registered in allowed_redirect_urls content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: OAuth provider not configured content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Provider already linked content: application/json: schema: $ref: '#/components/schemas/Error' /auth/oauth/{provider}/unlink: delete: tags: - OAuth Authentication summary: Unlink OAuth provider description: | Remove OAuth provider from user's account. Cannot unlink if it's the only authentication method. operationId: authUnlinkOAuthProvider security: - AuthUserAccessToken: [] parameters: - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple responses: '204': description: Provider unlinked '400': description: Cannot unlink last authentication method content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Provider not linked content: application/json: schema: $ref: '#/components/schemas/Error' /auth/oauth/{provider}/refresh-token: post: tags: - OAuth Authentication summary: Refresh OAuth provider token description: | Refresh the access token for an OAuth provider using its refresh token. Allows calling provider APIs on user's behalf (e.g., Google Drive, GitHub repos). operationId: refreshOAuthProviderToken security: - AuthUserAccessToken: [] parameters: - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple responses: '200': description: Token refreshed successfully content: application/json: schema: type: object properties: message: type: string provider: type: string expires_in: type: integer '400': description: No refresh token available or refresh failed content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Provider not linked content: application/json: schema: $ref: '#/components/schemas/Error' /auth/oauth/{provider}/token: get: tags: - OAuth Authentication summary: Get current provider access token description: | Get valid access token for OAuth provider. Automatically refreshes if expired. operationId: getOAuthProviderToken security: - AuthUserAccessToken: [] parameters: - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple responses: '200': description: Current access token content: application/json: schema: type: object properties: message: type: string provider: type: string expires_in: type: integer '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Provider not linked content: application/json: schema: $ref: '#/components/schemas/Error' /auth/oauth/{provider}/call-api: post: tags: - OAuth Authentication summary: Call OAuth provider API description: | Make an authenticated request to an OAuth provider's API on behalf of the user. The user's stored access token is automatically used and refreshed if needed. The request is always sent to the provider's fixed API base URL joined with the caller-supplied `endpoint`. `endpoint` must be a relative path beginning with `/` (optionally with a query string); it cannot change the target host. Absolute URLs, protocol-relative `//host` values, or userinfo (`@host`) are rejected with `400` so the request can never be redirected to another host. Examples of `endpoint`: - Google userinfo: `/oauth2/v1/userinfo` - GitHub repositories: `/user/repos` - Microsoft Graph profile: `/me` The response wraps the provider's raw JSON value with request metadata. An empty provider body is represented as `data: null`; the envelope preserves the provider's HTTP status in `status_code`, including errors. Provider response bodies are limited to 8 MiB after decompression. Transport failures, invalid JSON (including invalid UTF-8), and oversized bodies return `502`. Provider redirects to another origin are blocked and return `400`. operationId: callOAuthProviderAPI security: - AuthUserAccessToken: [] parameters: - name: provider in: path required: true schema: type: string enum: - google - github - microsoft - apple requestBody: required: true content: application/json: schema: type: object required: - endpoint properties: endpoint: type: string description: | Relative path on the provider's API, beginning with `/`. It is joined with the provider's fixed base URL; it must not contain a scheme, host, userinfo, or a leading `//`. example: /user/repos method: type: string enum: - GET - POST default: GET description: HTTP method to use body: type: object additionalProperties: true description: Request body for POST requests responses: '200': description: Provider API response content: application/json: schema: type: object description: OAuth provider API response envelope required: - provider - endpoint - status_code - data properties: provider: type: string enum: - google - github - microsoft - apple endpoint: type: string status_code: type: integer minimum: 100 maximum: 599 data: description: Raw provider JSON value, or null when the provider returns no body nullable: true '400': description: | Invalid request (for example: missing `endpoint`, an `endpoint` that is not a relative path, or an unsupported HTTP method), or a provider redirect to another origin. content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Not authenticated content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: OAuth provider configuration not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Failed to create the provider API request content: application/json: schema: $ref: '#/components/schemas/Error' '502': description: Provider transport failure, invalid JSON, or response body larger than 8 MiB content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/anon-keys: get: tags: - Anon Keys summary: List anon keys description: | Supports two mutually exclusive pagination modes. Offset mode uses `page` and `limit` and is the default when neither `cursor` nor `search` is supplied (first page, default `limit`). Cursor mode uses `cursor` and `limit`, supports `search` (case-insensitive name match), and returns `next_cursor`. Sending both `page` and `cursor` (or `page` and `search`) returns 400. operationId: listAnonKeys security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' responses: '200': description: List of anon keys content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/AnonKey' total: type: integer description: Total number of items matching the query (so the UI can render numbered pages). has_more: type: boolean description: Whether a next page exists. next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. post: tags: - Anon Keys summary: Create anon key operationId: createAnonKey security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: type: object required: - name properties: name: type: string description: | Key name for identification. Can only contain letters, numbers, underscores, and hyphens. pattern: ^[A-Za-z0-9_-]+$ minLength: 1 maxLength: 255 example: frontend-app permissions: type: array items: type: string enum: - auth.signup - auth.signin - auth.refresh - auth.logout - auth.password_reset - auth.confirm_email - auth.resend_confirmation - storage.upload - storage.download - storage.list - storage.delete - realtime.connect - realtime.subscribe - realtime.publish - functions.invoke description: | Optional list of permissions for this key. If not provided, defaults to auth-only permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation. Storage, realtime, and functions permissions must be explicitly added if needed. example: - auth.signup - auth.signin - auth.refresh - auth.logout responses: '201': description: Anon key created content: application/json: schema: $ref: '#/components/schemas/AnonKey' /projects/{id}/anon-keys/{keyId}: get: tags: - Anon Keys summary: Get anon key description: Get details of a specific anon key operationId: getAnonKey security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: keyId in: path required: true schema: type: string format: uuid responses: '200': description: Anon key details content: application/json: schema: $ref: '#/components/schemas/AnonKey' '404': description: Key not found delete: tags: - Anon Keys summary: Revoke anon key description: Revokes key - it will immediately stop working operationId: revokeAnonKey security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: keyId in: path required: true schema: type: string format: uuid responses: '204': description: Key revoked '401': description: Unauthorized '403': description: Forbidden '404': description: Key not found '409': description: Cannot delete the project's default anon key content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/anon-keys/{keyId}/regenerate: post: tags: - Anon Keys summary: Regenerate anon key description: Generate new JWT value for existing key operationId: regenerateAnonKey security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: keyId in: path required: true schema: type: string format: uuid responses: '200': description: Key regenerated content: application/json: schema: $ref: '#/components/schemas/AnonKey' /projects/{id}/anon-keys/{keyId}/set-default: post: tags: - Anon Keys summary: Set default anon key description: Promotes the given key to the project's configured default. At most one key per project can be default. operationId: setDefaultAnonKey security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: keyId in: path required: true schema: type: string format: uuid responses: '200': description: Key set as default content: application/json: schema: $ref: '#/components/schemas/AnonKey' '401': description: Unauthorized '403': description: Forbidden '404': description: Anon key not found '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/service-keys: get: tags: - Service Keys summary: List service keys (paginated) description: | List all service role keys for a project with pagination. **WARNING:** Service keys bypass RLS - for backend/admin use only! operationId: listServiceKeys security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' responses: '200': description: Paginated list of service keys content: application/json: schema: $ref: '#/components/schemas/PaginatedServiceKeys' post: tags: - Service Keys summary: Create service key description: | Create a new service role key for admin operations. **WARNING:** Service keys bypass all RLS policies! Store securely and NEVER expose in frontend code. operationId: createServiceKey security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: type: object required: - name properties: name: type: string description: | Descriptive name for the key (e.g., "admin-dashboard", "background-jobs"). Can only contain letters, numbers, underscores, and hyphens. pattern: ^[A-Za-z0-9_-]+$ minLength: 1 maxLength: 255 example: admin-dashboard permissions: type: array items: type: string description: | Optional least-privilege scope for the key. When omitted, empty, or containing only blank strings, the key is granted full access (["*"]) for backward compatibility. Provide an explicit list (e.g. ["functions.invoke", "locks.manage"]) to restrict the key; "*" grants everything. Scope enforcement applies to function invocation, storage object operations, and project locks. example: - functions.invoke - locks.manage responses: '201': description: Service key created - save the key_value immediately! content: application/json: schema: $ref: '#/components/schemas/ServiceKey' '409': description: Key with this name already exists /projects/{id}/service-keys/{keyId}: get: tags: - Service Keys summary: Get service key description: Get details of a specific service key operationId: getServiceKey security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: keyId in: path required: true schema: type: string format: uuid responses: '200': description: Service key details content: application/json: schema: $ref: '#/components/schemas/ServiceKey' '404': description: Key not found delete: tags: - Service Keys summary: Delete service key description: | Permanently delete a service key. Any services using this key will immediately lose access. operationId: deleteServiceKey security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: keyId in: path required: true schema: type: string format: uuid responses: '204': description: Key deleted /projects/{id}/service-keys/{keyId}/regenerate: post: tags: - Service Keys summary: Regenerate service key description: | Generate new JWT value for existing key. The old key is immediately invalidated. Update your backend services with the new key before regenerating in production. operationId: regenerateServiceKey security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: keyId in: path required: true schema: type: string format: uuid responses: '200': description: Key regenerated - save the new key_value immediately! content: application/json: schema: $ref: '#/components/schemas/ServiceKey' /projects/{id}/storage/buckets: get: tags: - Storage Buckets summary: List all storage buckets in a project description: | With no pagination params, returns the full bucket list as a bare array (legacy). Supplying `cursor`, `ending_before`, `search`, or `limit` switches to keyset (cursor) pagination and returns a paginated envelope with `next_cursor`/`prev_cursor` and a filtered `total`. operationId: listStorageBuckets security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' responses: '200': description: | Either the full bucket list (bare array, legacy) or a paginated envelope when cursor pagination is requested. content: application/json: schema: oneOf: - type: array items: $ref: '#/components/schemas/StorageBucket' - $ref: '#/components/schemas/PaginatedStorageBuckets' post: tags: - Storage Buckets summary: Create a new storage bucket operationId: createStorageBucket security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateStorageBucketRequest' responses: '201': description: Bucket created content: application/json: schema: $ref: '#/components/schemas/StorageBucket' '409': description: Bucket already exists /projects/{id}/storage/buckets/{bucketName}: get: tags: - Storage Buckets summary: Get storage bucket by name operationId: getStorageBucket security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/BucketName' responses: '200': description: Bucket details content: application/json: schema: $ref: '#/components/schemas/StorageBucket' '404': description: Bucket not found patch: tags: - Storage Buckets summary: Update storage bucket settings operationId: updateStorageBucket security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/BucketName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateStorageBucketRequest' responses: '200': description: Bucket updated content: application/json: schema: $ref: '#/components/schemas/StorageBucket' delete: tags: - Storage Buckets summary: Delete storage bucket and all objects operationId: deleteStorageBucket security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/BucketName' responses: '200': description: Bucket deleted /projects/{id}/storage/buckets/{bucketName}/policies: get: tags: - Storage Policies summary: List storage policies for a bucket operationId: listStoragePolicies security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/BucketName' responses: '200': description: List of policies content: application/json: schema: type: array items: $ref: '#/components/schemas/StoragePolicy' post: tags: - Storage Policies summary: Create a storage policy operationId: createStoragePolicy security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/BucketName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateStoragePolicyRequest' responses: '201': description: Policy created content: application/json: schema: $ref: '#/components/schemas/StoragePolicy' /projects/{id}/storage/buckets/{bucketName}/policies/{policyId}: delete: tags: - Storage Policies summary: Delete a storage policy operationId: deleteStoragePolicy security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - $ref: '#/components/parameters/BucketName' - name: policyId in: path required: true schema: type: string format: uuid responses: '200': description: Policy deleted /projects/{id}/storage/objects: get: tags: - Storage Admin summary: List all storage objects in a project description: | Returns a paginated list of all storage objects across all buckets in the project. Supports filtering by owner and pagination. operationId: listStorageObjectsAdmin security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' - name: owner_id in: query description: Filter by owner user ID schema: type: string format: uuid - name: page in: query description: Page number (1-based) schema: type: integer default: 1 minimum: 1 - name: limit in: query description: Items per page schema: type: integer default: 50 minimum: 1 maximum: 100 - $ref: '#/components/parameters/Cursor' - $ref: '#/components/parameters/EndingBefore' - $ref: '#/components/parameters/Offset' - $ref: '#/components/parameters/Search' responses: '200': description: Paginated list of storage objects content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/StorageObjectWithBucket' page: type: integer limit: type: integer total: type: integer has_more: type: boolean next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. /projects/{id}/storage/stats: get: tags: - Storage Admin summary: Get storage statistics for a project description: Returns aggregate storage statistics including bucket count, object count, and total size. operationId: getStorageStats security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Storage statistics content: application/json: schema: $ref: '#/components/schemas/StorageStats' /projects/{id}/realtime/config: get: tags: - Realtime summary: Get realtime configuration for a project description: Returns the realtime configuration including enabled features and limits. operationId: getRealtimeConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Realtime configuration content: application/json: schema: $ref: '#/components/schemas/RealtimeConfig' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Project not found content: application/json: schema: $ref: '#/components/schemas/Error' put: tags: - Realtime summary: Update realtime configuration for a project description: Updates realtime settings including feature toggles and limits. operationId: updateRealtimeConfig security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateRealtimeConfigRequest' responses: '200': description: Updated realtime configuration content: application/json: schema: $ref: '#/components/schemas/RealtimeConfig' '400': description: Invalid configuration values content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/realtime/stats: get: tags: - Realtime summary: Get realtime statistics for a project description: Returns realtime usage statistics including connection counts and subscribed tables. operationId: getRealtimeStats security: - UserToken: [] parameters: - $ref: '#/components/parameters/ProjectId' responses: '200': description: Realtime statistics content: application/json: schema: $ref: '#/components/schemas/RealtimeStats' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error' /storage/{bucketName}: get: tags: - Storage Objects summary: List objects in a bucket operationId: listStorageObjects security: - AnonKey: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/BucketName' - name: prefix in: query description: Filter objects by path prefix schema: type: string - name: limit in: query description: Maximum objects to return schema: type: integer default: 50 maximum: 1000 - name: cursor in: query description: Pagination cursor schema: type: string responses: '200': description: List of objects content: application/json: schema: $ref: '#/components/schemas/StorageListResponse' '403': description: Access denied by storage policy '429': $ref: '#/components/responses/BandwidthCapExceeded' /locks/{key}/lease: post: tags: - Locks summary: Acquire a project lock description: | Acquires a project-scoped lease using the project embedded in the service-role key. The caller must hold the `locks.manage` permission. Repeating the request with the same lock token is idempotent and resets that lease to the requested TTL. A different live owner receives `409 lock_held`; a caller whose own lease already lapsed receives `409 lock_ownership_lost`. operationId: acquireProjectLock security: - ServiceRoleKey: [] parameters: - $ref: '#/components/parameters/LockKey' - $ref: '#/components/parameters/LockToken' - $ref: '#/components/parameters/LockRequestId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ProjectLockLeaseRequest' responses: '201': description: Lease acquired content: application/json: schema: $ref: '#/components/schemas/ProjectLockLease' '400': description: Invalid lock key, token, or TTL content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Missing or invalid credentials content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: A non-service credential was supplied or the service key lacks `locks.manage` content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: | The lock is held by another live lease (`lock_held`), or the caller's own lease lapsed and is not yet reclaimable (`lock_ownership_lost`). content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Project lock request limit exceeded headers: Retry-After: description: Seconds until the current fixed-minute window ends. schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Lock service unavailable content: application/json: schema: $ref: '#/components/schemas/Error' patch: tags: - Locks summary: Renew a project lock description: | Renews a lease owned by the supplied lock token. The request must arrive more than one second before `expires_at`; this safety margin prevents clock skew between regional API instances from resurrecting an expired lease. operationId: renewProjectLock security: - ServiceRoleKey: [] parameters: - $ref: '#/components/parameters/LockKey' - $ref: '#/components/parameters/LockToken' - $ref: '#/components/parameters/LockRequestId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ProjectLockLeaseRequest' responses: '200': description: Lease renewed content: application/json: schema: $ref: '#/components/schemas/ProjectLockLease' '400': description: Invalid lock key, token, or TTL content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Missing or invalid credentials content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: A non-service credential was supplied or the service key lacks `locks.manage` content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: The lease expired or is owned by another token content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Project lock request limit exceeded headers: Retry-After: description: Seconds until the current fixed-minute window ends. schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Lock service unavailable content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Locks summary: Release a project lock description: Releases a lease only when the supplied lock token still owns it. operationId: releaseProjectLock security: - ServiceRoleKey: [] parameters: - $ref: '#/components/parameters/LockKey' - $ref: '#/components/parameters/LockToken' - $ref: '#/components/parameters/LockRequestId' responses: '204': description: Lease released '400': description: Invalid lock key or token content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Missing or invalid credentials content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: A non-service credential was supplied or the service key lacks `locks.manage` content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: The lease is owned by another token content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Project lock request limit exceeded headers: Retry-After: description: Seconds until the current fixed-minute window ends. schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Lock service unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /locks/{key}: get: tags: - Locks summary: Read a project lock description: | Reports whether the lock is currently held, when its lease expires, and the holder's fencing token. `held` follows takeover eligibility rather than raw expiry, so `held: false` means an acquire would succeed now. No lock token is required, making this usable for monitoring and recovery. operationId: getProjectLock security: - ServiceRoleKey: [] parameters: - $ref: '#/components/parameters/LockKey' - $ref: '#/components/parameters/LockRequestId' responses: '200': description: Current lock state content: application/json: schema: $ref: '#/components/schemas/ProjectLockState' '400': description: Invalid lock key content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Missing or invalid credentials content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: A non-service credential was supplied or the service key lacks `locks.manage` content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Project lock request limit exceeded headers: Retry-After: description: Seconds until the current fixed-minute window ends. schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Lock service unavailable content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Locks summary: Force release a project lock description: | Drops the lease whatever token holds it, for recovering a lock whose holder died without releasing. Use `DELETE /locks/{key}/lease` for normal release. This breaks mutual exclusion by itself: the previous holder keeps working until its own renewal fails. Guard the protected resource with the lease's `fencing_token`, which the next acquisition raises, so a write from the displaced holder can be rejected. Succeeds when the lock is already absent. operationId: forceReleaseProjectLock security: - ServiceRoleKey: [] parameters: - $ref: '#/components/parameters/LockKey' - $ref: '#/components/parameters/LockRequestId' responses: '204': description: Lock released '400': description: Invalid lock key content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Missing or invalid credentials content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: A non-service credential was supplied or the service key lacks `locks.manage` content: application/json: schema: $ref: '#/components/schemas/Error' '429': description: Project lock request limit exceeded headers: Retry-After: description: Seconds until the current fixed-minute window ends. schema: type: integer content: application/json: schema: $ref: '#/components/schemas/Error' '503': description: Lock service unavailable content: application/json: schema: $ref: '#/components/schemas/Error' /storage/{bucketName}/move: post: tags: - Storage Objects summary: Move/rename an object operationId: moveStorageObject security: - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/BucketName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/StorageMoveRequest' responses: '200': description: Object moved content: application/json: schema: $ref: '#/components/schemas/StorageObject' '403': description: Access denied by storage policy '429': $ref: '#/components/responses/BandwidthCapExceeded' /storage/{bucketName}/copy: post: tags: - Storage Objects summary: Copy an object operationId: copyStorageObject security: - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/BucketName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/StorageCopyRequest' responses: '201': description: Object copied content: application/json: schema: $ref: '#/components/schemas/StorageObject' '403': description: Access denied by storage policy '429': $ref: '#/components/responses/BandwidthCapExceeded' /storage/{bucketName}/{path}: post: tags: - Storage Objects summary: Upload a file or create resumable session description: | Unified endpoint for file uploads. Behavior depends on Content-Type and headers: **Simple Upload (multipart/form-data):** Upload a complete file in a single request. Best for files under 100MB. **Create Resumable Session (application/json):** Create a session for chunked uploads. Best for large files or unreliable networks. Requires: `Content-Type: application/json` with body `{"filename": "...", "content_type": "...", "total_size": ...}` **Complete Resumable Session:** Complete a session after all parts are uploaded. Requires: `X-Upload-Session` header with session ID and `X-Upload-Complete: true` header. **Resumable Session Ownership:** A session created with a user access token remains bound to that user. A session created with an anon key remains bound to that exact anon key. Reuse the same identity or anon key for part uploads, status, completion, and abort requests; an ownership mismatch returns `404`. operationId: uploadStorageObject security: - AnonKey: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/BucketName' - name: path in: path required: true description: Object path within bucket schema: type: string - name: X-Upload-Session in: header required: false description: Upload session ID (for completing resumable uploads) schema: type: string - name: X-Upload-Complete in: header required: false description: Set to "true" to complete a resumable upload session schema: type: string enum: - 'true' requestBody: required: true content: multipart/form-data: schema: type: object required: - file properties: file: type: string format: binary description: File to upload (simple upload) application/json: schema: $ref: '#/components/schemas/CreateUploadSessionRequest' responses: '200': description: Resumable upload completed (when X-Upload-Complete=true) content: application/json: schema: $ref: '#/components/schemas/CompleteUploadSessionResponse' '201': description: File uploaded or session created content: application/json: schema: oneOf: - $ref: '#/components/schemas/StorageObject' - $ref: '#/components/schemas/CreateUploadSessionResponse' '400': description: | Bad request. This can occur when: - MIME type is not in the bucket's allowed_mime_types list - File exceeds the bucket's configured file_size_limit - File exceeds the global maximum upload size (5GB) - Invalid request body or missing required fields '403': description: Access denied by storage policy '404': description: Resumable upload session not found or not owned by this credential '413': description: | File size exceeds plan-based limits. This occurs when: - File exceeds the plan-based maximum file size (HOBBY or SUPERAGENT tier) - Upload would exceed the project's total storage quota '429': $ref: '#/components/responses/BandwidthCapExceeded' put: tags: - Storage Objects summary: Upload a part of a resumable upload description: | Upload a single part of a resumable upload session. **Requirements:** - Part numbers start at 1 - All parts except the last must be at least 5MB - Maximum part size is 25MB - Parts can be uploaded in any order - Re-uploading a part overwrites the previous upload - Anonymous sessions must reuse the exact anon key that created the session operationId: uploadPart security: - AnonKey: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/BucketName' - name: path in: path required: true description: Object path within bucket schema: type: string - name: X-Upload-Session in: header required: true description: Upload session ID schema: type: string - name: X-Part-Number in: header required: true description: Part number (1 to 10000) schema: type: integer minimum: 1 maximum: 10000 requestBody: required: true content: application/octet-stream: schema: type: string format: binary responses: '200': description: Part uploaded content: application/json: schema: $ref: '#/components/schemas/UploadSessionPart' '400': description: Invalid part number or part data '403': description: Access denied '404': description: Session not found or not owned by this credential get: tags: - Storage Objects summary: Download a file or get upload session status description: | Download a file, or get the status of a resumable upload session. **File Download (default):** Downloads the file at the specified path. **Session Status (with X-Upload-Session header):** Returns the status of a resumable upload session, including which parts have been uploaded. Anonymous sessions must reuse the exact anon key that created the session. operationId: downloadStorageObject security: - AnonKey: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/BucketName' - name: path in: path required: true description: Object path within bucket schema: type: string - name: Range in: header required: false description: | HTTP Range header for partial downloads. Format: bytes=start-end or bytes=start- Examples: bytes=0-1023, bytes=1000- schema: type: string pattern: ^bytes=\d+-\d*$ - name: X-Upload-Session in: header required: false description: Upload session ID (to get session status instead of downloading) schema: type: string responses: '200': description: File content or session status headers: Content-Type: schema: type: string Content-Length: schema: type: integer ETag: schema: type: string content: application/octet-stream: schema: type: string format: binary application/json: schema: $ref: '#/components/schemas/UploadSessionStatusResponse' '206': description: Partial content (range request) '400': description: Invalid Range header format '403': description: Access denied by storage policy '404': description: Object or session not found, or session not owned by this credential '429': $ref: '#/components/responses/BandwidthCapExceeded' delete: tags: - Storage Objects summary: Delete a file or abort upload session description: | Delete a file, or abort a resumable upload session. **File Delete (default):** Deletes the file at the specified path. **Abort Session (with X-Upload-Session header):** Aborts a resumable upload session and cleans up any uploaded parts. Anonymous sessions must reuse the exact anon key that created the session. operationId: deleteStorageObject security: - AnonKey: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/BucketName' - name: path in: path required: true description: Object path within bucket schema: type: string - name: X-Upload-Session in: header required: false description: Upload session ID (to abort session instead of deleting file) schema: type: string responses: '200': description: Object deleted or session aborted '403': description: Access denied by storage policy '404': description: Object or session not found, or session not owned by this credential '429': $ref: '#/components/responses/BandwidthCapExceeded' /storage/{bucketName}/{path}/visibility: patch: tags: - Storage Objects summary: Update file visibility (public/private) description: | Change whether a file is publicly accessible. Only the file owner or a service key can change visibility. If the bucket defines UPDATE policies, the owner must also satisfy one of them. - Public files can be downloaded with just an anon key (no user authentication required) - Private files (default) require authentication and must pass policy checks - All downloads go through the Volcano API - there is no direct access to the underlying store operationId: updateStorageObjectVisibility security: - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - $ref: '#/components/parameters/BucketName' - name: path in: path required: true description: Object path within bucket schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/StorageVisibilityRequest' responses: '200': description: Visibility updated content: application/json: schema: $ref: '#/components/schemas/StorageObject' '403': description: Not the file owner or denied by the bucket's UPDATE policies '404': description: Object not found /public/{projectId}/{bucketName}/{path}: get: tags: - Storage Objects summary: Download a public file (no authentication required) description: | Download a file that has been marked as public. This endpoint requires NO authentication. **Access Requirements:** - The file must have `is_public: true` set via the visibility endpoint - Private files will return 403 Forbidden **Use Cases:** - Shareable public URLs for profile pictures, public documents, etc. - Embedding public files on external websites - Direct linking without requiring SDK or authentication **URL Format:** ``` GET /public/{projectId}/{bucketName}/{path} ``` **Example:** ``` https://api.volcano.dev/public/abc123/avatars/user-photo.jpg ``` **CORS:** This endpoint allows all origins since the file is already public. operationId: downloadPublicFile parameters: - name: projectId in: path required: true description: Project ID schema: type: string format: uuid - $ref: '#/components/parameters/BucketName' - name: path in: path required: true description: Object path within bucket schema: type: string responses: '200': description: File content content: '*/*': schema: type: string format: binary '206': description: Partial content (range request) '404': description: Not found (file doesn't exist or is not public) '429': $ref: '#/components/responses/BandwidthCapExceeded' /health: get: tags: - System summary: Health check endpoint description: Returns server health status. Used for load balancer and monitoring checks. operationId: healthCheck responses: '200': description: Server is healthy content: text/plain: schema: type: string example: OK /sandboxes/presets: get: tags: - Sandboxes summary: List available sandbox presets operationId: listSandboxPresets security: [] responses: '200': description: List available sandbox presets content: application/json: schema: $ref: '#/components/schemas/SandboxPresetList' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/sandboxes: get: tags: - Sandboxes summary: List sandbox templates operationId: listSandboxes security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: id in: path required: true schema: type: string format: uuid - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' responses: '200': description: List sandbox templates content: application/json: schema: $ref: '#/components/schemas/SandboxTemplatePage' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Sandboxes summary: Create a sandbox template from a verified preset operationId: createSandbox security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: Idempotency-Key in: header required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateSandboxTemplateRequest' responses: '201': description: Create a sandbox template from a verified preset content: application/json: schema: $ref: '#/components/schemas/SandboxTemplate' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/sandboxes/{sandboxId}: get: tags: - Sandboxes summary: Get a sandbox template operationId: getSandbox security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: sandboxId in: path required: true schema: type: string format: uuid responses: '200': description: Get a sandbox template content: application/json: schema: $ref: '#/components/schemas/SandboxTemplate' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' patch: tags: - Sandboxes summary: Rename a sandbox template operationId: updateSandbox security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: sandboxId in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateSandboxTemplateRequest' responses: '200': description: Rename a sandbox template content: application/json: schema: $ref: '#/components/schemas/SandboxTemplate' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Sandboxes summary: Retire a template and terminate its sessions operationId: deleteSandbox security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: sandboxId in: path required: true schema: type: string format: uuid responses: '202': description: Retire a template and terminate its sessions default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/sandboxes/{sandboxId}/deployments: get: tags: - Sandboxes summary: List sandbox deployment history operationId: listSandboxDeployments security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: sandboxId in: path required: true schema: type: string format: uuid - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' responses: '200': description: List sandbox deployment history content: application/json: schema: $ref: '#/components/schemas/SandboxDeploymentPage' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/sandbox-sessions: get: tags: - Sandboxes summary: List project sandbox sessions operationId: listSandboxSessions security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: id in: path required: true schema: type: string format: uuid - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Cursor' responses: '200': description: List project sandbox sessions content: application/json: schema: $ref: '#/components/schemas/SandboxSessionPage' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' post: tags: - Sandboxes summary: Start a sandbox session operationId: createSandboxSession security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: Idempotency-Key in: header required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateSandboxSessionRequest' responses: '201': description: Start a sandbox session content: application/json: schema: $ref: '#/components/schemas/SandboxSession' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /projects/{id}/sandbox-executions: post: tags: - Sandboxes summary: Execute once and return after confirmed termination operationId: executeSandbox security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: Idempotency-Key in: header required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SandboxExecutionRequest' responses: '200': description: Execute once and return after confirmed termination content: application/json: schema: $ref: '#/components/schemas/SandboxExecutionResult' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /sandbox-sessions/{sessionId}: get: tags: - Sandboxes summary: Get a sandbox session operationId: getSandboxSession security: - UserToken: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid responses: '200': description: Get a sandbox session content: application/json: schema: $ref: '#/components/schemas/SandboxSession' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Sandboxes summary: Request sandbox termination operationId: terminateSandboxSession security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid responses: '202': description: Request sandbox termination content: application/json: schema: $ref: '#/components/schemas/SandboxSession' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /sandbox-sessions/{sessionId}/suspend: post: tags: - Sandboxes summary: Suspend a sandbox session operationId: suspendSandboxSession security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid responses: '202': description: Suspend a sandbox session content: application/json: schema: $ref: '#/components/schemas/SandboxSession' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /sandbox-sessions/{sessionId}/resume: post: tags: - Sandboxes summary: Resume a sandbox session operationId: resumeSandboxSession security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid responses: '202': description: Resume a sandbox session content: application/json: schema: $ref: '#/components/schemas/SandboxSession' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /sandbox-sessions/{sessionId}/exec: post: tags: - Sandboxes summary: Execute a command within a session operationId: executeSandboxSession security: - UserToken: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid - name: Idempotency-Key in: header required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SandboxCommandRequest' responses: '200': description: Execute a command within a session content: application/json: schema: $ref: '#/components/schemas/SandboxCommandResult' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /sandbox-sessions/{sessionId}/files/read: post: tags: - Sandboxes summary: Read a workspace file operationId: readSandboxSessionFile security: - UserToken: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SandboxFileReadRequest' responses: '200': description: Read a workspace file content: application/json: schema: $ref: '#/components/schemas/SandboxFileResult' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /sandbox-sessions/{sessionId}/files/write: post: tags: - Sandboxes summary: Write a workspace file operationId: writeSandboxSessionFile security: - UserToken: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SandboxFileWriteRequest' responses: '204': description: Write a workspace file default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /sandbox-sessions/{sessionId}/grants/{subjectId}: put: tags: - Sandboxes summary: Authorize an authenticated project user for this session operationId: grantSandboxSession security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid - name: subjectId in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SandboxSubjectGrantRequest' responses: '204': description: Authorize an authenticated project user for this session default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' delete: tags: - Sandboxes summary: Revoke a project user session grant operationId: revokeSandboxSession security: - UserToken: [] - ServiceRoleKey: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid - name: subjectId in: path required: true schema: type: string format: uuid responses: '204': description: Revoke a project user session grant default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' /sandbox-sessions/{sessionId}/access: post: tags: - Sandboxes summary: Issue a short-lived port-scoped access credential operationId: createSandboxSessionAccess security: - UserToken: [] - ServiceRoleKey: [] - AuthUserAccessToken: [] parameters: - name: sessionId in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SandboxAccessRequest' responses: '200': description: Issue a short-lived port-scoped access credential content: application/json: schema: $ref: '#/components/schemas/SandboxAccess' default: description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). content: application/json: schema: $ref: '#/components/schemas/Error' components: securitySchemes: AnonKey: type: http scheme: bearer bearerFormat: JWT description: | Project-specific public key for frontend authentication. Required for signup, signin, refresh, and logout endpoints. Get from Project Settings → Authentication → Anon Keys. Safe to expose in frontend code (scoped to project, limited permissions). AuthUserAccessToken: type: http scheme: bearer bearerFormat: JWT description: | Auth user access token obtained from signup/signin. Used for authenticated function invocation and user profile access. Functions invoked with access tokens receive user context in event.__volcano_auth. Expires after configured lifetime (default: 1 hour). ServiceRoleKey: type: http scheme: bearer bearerFormat: JWT description: | Service role key for admin operations. **WARNING:** Bypasses Row-Level Security - backend use only! Create via POST /projects/{id}/service-keys. Used for function invocation with full database access. UserToken: type: http scheme: bearer bearerFormat: JWT description: | Platform user token from the Management API. Required for project management operations. Obtain via POST /tokens in Management API (port 8001). parameters: BackupName: name: backupName in: path required: true schema: type: string minLength: 1 maxLength: 128 description: | Backup name, unique within the database, exactly as returned by the list endpoint. Deliberately looser than the names you can create: a backup made by a schedule is named for you, so reading or deleting one accepts any name a backup can have. BranchName: name: branchName in: path required: true schema: type: string pattern: ^[a-z0-9_]+$ maxLength: 64 description: Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) BucketName: name: bucketName in: path required: true schema: type: string pattern: ^[a-zA-Z0-9_-]+$ minLength: 1 maxLength: 64 description: Storage bucket name Cursor: name: cursor in: query required: false schema: type: string description: | Opaque keyset pagination cursor from a previous response's `next_cursor` — pages forward. Mutually exclusive with `page` and `ending_before`; combining them returns 400. When supplied, the request's `search` and `limit` must match the values bound to the cursor or the request returns 400. EndingBefore: name: ending_before in: query required: false schema: type: string description: | Opaque keyset pagination cursor from a previous response's `prev_cursor` — pages backward (the page immediately preceding this cursor). Mutually exclusive with `page` and `cursor`; combining them returns 400. `search` and `limit` must match the values bound to the cursor or the request returns 400. DatabaseName: name: databaseName in: path required: true schema: type: string pattern: ^[a-z0-9_]+$ maxLength: 64 description: Database name (unique within project, lowercase letters, numbers, and underscores only) DeploymentId: name: deploymentId in: path required: true schema: type: string format: uuid description: Frontend deployment ID FrontendId: name: frontendId in: path required: true schema: type: string format: uuid description: Frontend ID FunctionId: name: functionId in: path required: true schema: type: string format: uuid description: Function ID DurableFunctionId: name: functionId in: path required: true schema: type: string description: Durable function ID, or its name within the project DurableExecutionId: name: executionId in: path required: true schema: type: string format: uuid description: Durable execution ID Limit: name: limit in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 10 description: Number of items per page (max 100) LockKey: name: key in: path required: true description: Project-local lock name. schema: type: string minLength: 1 maxLength: 128 pattern: ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$ LockToken: name: X-Volcano-Lock-Token in: header required: true description: Opaque UUID generated once by the caller and retained for the lease lifetime. schema: type: string format: uuid LockRequestId: name: X-Volcano-Request-Id in: header required: true description: | UUID correlating this request across client and server logs. Repeat safety comes from the lock token, so a retry under a reused request ID still counts against the quota. schema: type: string format: uuid DeploymentOperation: name: operation in: query required: false description: Restrict a deployment feed to one kind of operation. schema: type: string enum: - deploy - redeploy - update - delete DeploymentOwnerId: name: owner_id in: query required: false description: | The user who owns the projects whose deployments to return (`projects.user_id`). This is ownership, not the actor that started the deployment — see `initiated_by_user_id` for that. Not a UUID: platform user ids are opaque strings. schema: type: string maxLength: 255 DeploymentOrder: name: order in: query required: false description: | Sort key and direction. `created_at.desc` (default) is the feed order. `completed_at.asc` orders finished attempts by completion, oldest first, and excludes attempts that never completed. schema: type: string enum: - created_at.desc - completed_at.asc default: created_at.desc DeploymentResourceType: name: resource_type in: query required: false description: | Restrict a deployment feed to a single resource type. Omit to return both Function and Frontend deployments. schema: type: string enum: - function - frontend DeploymentStatus: name: status in: query required: false description: Restrict a deployment feed to attempts in one status. schema: type: string enum: - queued - provisioning - active - degraded - failed - superseded - deleting - deleted Offset: name: offset in: query required: false schema: type: integer minimum: 0 default: 0 description: | Bounded row offset past the keyset anchor named by `cursor` (forward) or `ending_before` (backward) — the hybrid jump. Seek to the anchor, then skip this many rows within. Used for numbered jump-to-page: from the current page, seek to its next/prev cursor and offset the remaining pages. Only honored on the cursor pagination path; ignored otherwise. Page: name: page in: query required: false schema: type: integer minimum: 1 description: | Page number (1-indexed) for offset pagination. Declares no schema default so the request validator does not inject one: handlers that omit `page` see it unset (nil) and default to 1 in code, while cursor-first endpoints (e.g. the project deployments feed) can detect its absence to stay in keyset/search mode. Supplying `page` selects offset pagination. ProjectId: name: id in: path required: true schema: type: string format: uuid description: Project ID Search: name: search in: query required: false schema: type: string maxLength: 256 description: | Case-insensitive substring match on the resource `name`. See the endpoint description for supported pagination modes. RestoreId: name: restoreId in: path required: true schema: type: string format: uuid description: Database restore ID SchedulerId: name: schedulerId in: path required: true schema: type: string format: uuid description: Function scheduler ID VariableName: name: name in: path required: true schema: type: string minLength: 1 maxLength: 256 pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ description: Variable name responses: BandwidthCapExceeded: description: | The platform user exceeded their billing-cycle bandwidth allowance (aggregate ingress + egress across owned projects). Enforcement is eventual: requests are rejected until the allowance increases or the next anniversary cycle begins. content: application/json: schema: $ref: '#/components/schemas/Error' DatabaseQueryCapExceeded: description: | The query was rejected by a billing-cycle allowance: either the owning platform user's bandwidth allowance (aggregate ingress + egress across owned projects) or their database-request allowance. Enforcement is eventual: queries are rejected until the allowance increases or the next anniversary cycle begins. The error message identifies the resource. content: application/json: schema: $ref: '#/components/schemas/Error' DatabaseBranchQueryUnavailable: description: | The branch exists but cannot serve queries: it is still provisioning, being reset, expired, or its parent is being restored. Distinct from `404` so a caller waiting on a branch can tell it apart from a typo. content: application/json: schema: $ref: '#/components/schemas/Error' schemas: SandboxPreset: type: object additionalProperties: false properties: id: type: string runtime: type: string version: type: string memory_mb: type: integer enum: - 1024 - 2048 regions: type: array items: type: string required: - id - runtime - version - memory_mb - regions SandboxTemplate: type: object additionalProperties: false properties: id: type: string format: uuid project_id: type: string format: uuid name: type: string pattern: ^[a-z][a-z0-9-]{0,62}$ preset: type: string memory_mb: type: integer status: type: string enum: - ready - unavailable - deleting created_at: type: string format: date-time required: - id - project_id - name - status - created_at CreateSandboxTemplateRequest: type: object additionalProperties: false properties: name: type: string pattern: ^[a-z][a-z0-9-]{0,62}$ preset: type: string description: Preset ID from the available Sandbox preset catalog. memory_mb: type: integer enum: - 1024 - 2048 default: 1024 required: - name - preset UpdateSandboxTemplateRequest: type: object additionalProperties: false properties: name: type: string pattern: ^[a-z][a-z0-9-]{0,62}$ required: - name SandboxSession: type: object additionalProperties: false properties: id: type: string format: uuid project_id: type: string format: uuid sandbox_id: type: string format: uuid state: type: string enum: - starting - running - suspending - suspended - resuming - terminating - terminated - unknown desired_state: type: string enum: - running - suspended - terminated region: type: string memory_mb: type: integer created_at: type: string format: date-time started_at: type: string format: date-time expires_at: type: string format: date-time required: - id - project_id - sandbox_id - state - desired_state - region - memory_mb - created_at - expires_at CreateSandboxSessionRequest: type: object additionalProperties: false properties: preset: type: string description: Preset ID from the available Sandbox preset catalog. sandbox_id: type: string format: uuid memory_mb: type: integer enum: - 1024 - 2048 region: type: string pattern: ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$ description: Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted. max_duration_seconds: type: integer minimum: 30 maximum: 28800 default: 3600 idle_timeout_seconds: type: integer minimum: 0 maximum: 28800 default: 0 required: - region oneOf: - required: - preset not: required: - sandbox_id - required: - sandbox_id not: required: - preset SandboxCommandRequest: type: object additionalProperties: false properties: command: type: string minLength: 1 maxLength: 65536 timeout_seconds: type: integer minimum: 1 maximum: 3600 default: 60 environment: type: object additionalProperties: type: string maxProperties: 64 required: - command SandboxExecutionRequest: type: object additionalProperties: false properties: preset: type: string description: Preset ID from the available Sandbox preset catalog. sandbox_id: type: string format: uuid memory_mb: type: integer enum: - 1024 - 2048 region: type: string pattern: ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$ description: Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted. command: type: string minLength: 1 maxLength: 65536 timeout_seconds: type: integer minimum: 1 maximum: 60 default: 60 environment: type: object additionalProperties: type: string maxProperties: 64 required: - region - command oneOf: - required: - preset not: required: - sandbox_id - required: - sandbox_id not: required: - preset SandboxCommandResult: type: object additionalProperties: false properties: stdout: type: string stderr: type: string exit_code: type: integer stdout_truncated: type: boolean stderr_truncated: type: boolean timed_out: type: boolean required: - stdout - stderr - exit_code - stdout_truncated - stderr_truncated - timed_out SandboxExecutionResult: type: object additionalProperties: false properties: stdout: type: string stderr: type: string exit_code: type: integer stdout_truncated: type: boolean stderr_truncated: type: boolean timed_out: type: boolean session_id: type: string format: uuid region: type: string duration_ms: type: integer format: int64 minimum: 0 required: - stdout - stderr - exit_code - stdout_truncated - stderr_truncated - timed_out - session_id - region - duration_ms SandboxFileWriteRequest: type: object additionalProperties: false properties: path: type: string minLength: 1 maxLength: 4096 data: type: string format: byte maxLength: 11184812 required: - path - data SandboxFileReadRequest: type: object additionalProperties: false properties: path: type: string minLength: 1 maxLength: 4096 required: - path SandboxFileResult: type: object additionalProperties: false properties: data: type: string format: byte required: - data SandboxSubjectGrantRequest: type: object additionalProperties: false properties: expires_at: type: string format: date-time required: - expires_at SandboxAccessRequest: type: object additionalProperties: false properties: port: type: integer minimum: 1 maximum: 65532 expires_in_seconds: type: integer minimum: 1 maximum: 300 default: 300 required: - port SandboxAccess: type: object additionalProperties: false properties: url: type: string format: uri token: type: string expires_at: type: string format: date-time required: - url - token - expires_at SandboxDeployment: type: object additionalProperties: false properties: id: type: string format: uuid status: type: string created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - status - created_at - updated_at SandboxPagination: type: object additionalProperties: false properties: limit: type: integer has_more: type: boolean next_cursor: type: string required: - limit - has_more SandboxTemplatePage: type: object additionalProperties: false properties: data: type: array items: $ref: '#/components/schemas/SandboxTemplate' pagination: $ref: '#/components/schemas/SandboxPagination' required: - data - pagination SandboxSessionPage: type: object additionalProperties: false properties: data: type: array items: $ref: '#/components/schemas/SandboxSession' pagination: $ref: '#/components/schemas/SandboxPagination' required: - data - pagination SandboxDeploymentPage: type: object additionalProperties: false properties: data: type: array items: $ref: '#/components/schemas/SandboxDeployment' pagination: $ref: '#/components/schemas/SandboxPagination' required: - data - pagination SandboxPresetList: type: object additionalProperties: false properties: data: type: array items: $ref: '#/components/schemas/SandboxPreset' required: - data SandboxCapacity: type: object additionalProperties: false properties: region: type: string allocated_memory_mb: type: integer format: int64 minimum: 0 required: - region - allocated_memory_mb SandboxCapacityList: type: object additionalProperties: false properties: data: type: array items: $ref: '#/components/schemas/SandboxCapacity' required: - data PublishSandboxPresetRequest: type: object additionalProperties: false properties: id: type: string format: uuid preset: type: string enum: - python3.12 - node22 memory_mb: type: integer enum: - 1024 - 2048 deployment_id: type: string format: uuid required: - id - preset - memory_mb - deployment_id AnonKey: type: object properties: id: type: string format: uuid project_id: type: string format: uuid name: type: string key_value: type: string description: JWT token - use this in frontend Authorization header permissions: type: array items: type: string description: | Permissions granted to this anon key. Auth permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation Storage permissions: storage.upload, storage.download, storage.list, storage.delete Realtime permissions: realtime.connect, realtime.subscribe, realtime.publish Functions permissions: functions.invoke example: - auth.signup - auth.signin - auth.refresh - auth.logout is_default: type: boolean description: Whether this is the project's configured default anon key. Only one key per project can be default. created_at: type: string format: date-time required: - id - name - key_value AuthConfig: type: object properties: project_id: type: string format: uuid access_token_lifetime: type: integer description: Access token lifetime in seconds default: 3600 refresh_token_lifetime: type: integer description: Refresh token lifetime in seconds default: 2592000 inactivity_timeout: type: integer description: Force re-login after inactivity (seconds, 0=never) default: 0 max_session_duration: type: integer description: Force re-login after duration (seconds, 0=never) default: 0 min_password_length: type: integer minimum: 15 maximum: 128 default: 15 description: Configured minimum password length in Unicode characters. password_policy: $ref: '#/components/schemas/AuthPasswordPolicy' require_uppercase: type: boolean default: false require_lowercase: type: boolean default: false require_numbers: type: boolean default: false require_special_chars: type: boolean default: false enable_signup: type: boolean description: Master switch - allow new user signups via ANY provider default: true enable_email_password: type: boolean description: Enable email/password authentication as a provider default: true rate_limit_signup: type: integer description: Signups per hour per IP default: 100 rate_limit_signin: type: integer description: Signins per hour per IP default: 100 rate_limit_token_refresh: type: integer description: Refreshes per hour per IP default: 1000 cors_enabled: type: boolean default: false cors_allowed_origins: type: array items: type: string example: - https://myapp.com - http://localhost:3000 enable_anonymous_signins: type: boolean description: Allow creating users without email/password default: false allowed_email_domains: type: array description: | Email domains allowed to create users in this project. Applies to email/password signup, OAuth/SSO signup, anonymous conversion, and email changes. Empty (the default) allows every domain. Entries are stored normalized (lowercase, no `@` prefix) and match the domain part exactly: `domain1.com` does not cover `mail.domain1.com`. Signups from other domains are rejected with 403, and `allowed_email_domains_mode` decides whether sign-in is covered as well. The allowlist is a SUPERAGENT feature to configure and to enforce. A downgrade parks it: the domains are still returned here and stop being applied until the project is back on SUPERAGENT. items: type: string example: - domain1.com - domain2.com allowed_email_domains_mode: type: string description: | How far `allowed_email_domains` reaches. `signup` only gates account creation, so accounts that predate the list keep signing in. `signup_and_signin` also refuses to issue a session to an account whose domain is not listed. `disabled` keeps the list without enforcing it. enum: - disabled - signup - signup_and_signin default: signup platform_token_ttl: type: integer description: TTL in seconds for platform tokens minted via `/auth/platform/exchange` default: 2592000 allow_password_reset: type: boolean description: Enable forgot password flow default: true password_reset_timeout: type: integer description: Recovery token expiry in seconds default: 3600 max_password_history: type: integer description: Number of previous passwords to remember (0=disabled) default: 0 cors_allow_credentials: type: boolean description: Allow credentials in CORS requests default: true cors_max_age: type: integer description: CORS preflight cache duration (seconds) default: 86400 require_email_confirmation: type: boolean description: Require users to confirm email before sign-in. Can only be true when email_enabled is true. default: false email_confirmation_timeout: type: integer description: Email confirmation token expiry in seconds. default: 86400 auto_link_verified_oauth: type: boolean description: Link a verified OAuth identity to an existing confirmed account with the same email instead of returning a conflict. Requires require_email_confirmation to be true. default: false email_enabled: type: boolean description: Enable transactional email sending (confirmation, reset, change notifications). Must be true when require_email_confirmation is true. default: false email_from_address: type: string email_from_name: type: string smtp_host: type: string smtp_port: type: integer default: 587 smtp_username: type: string smtp_password_configured: type: boolean description: Whether an SMTP password is configured. The password itself is never returned. default: false smtp_use_tls: type: boolean default: true email_confirmation_subject: type: string email_password_reset_subject: type: string email_password_changed_subject: type: string managed_auth_enabled: type: boolean description: Enables project-hosted managed auth pages. default: false post_auth_redirect_url: type: string description: Default redirect target after successful hosted auth. allowed_redirect_urls: type: array description: Redirect allowlist used to validate post_auth_redirect_url and post_logout_redirect_url. items: type: string post_logout_redirect_url: type: string description: Redirect target after logout from hosted pages. device_verification_url: type: string description: | Optional override for the device-authorization verification page. When set, POST /auth/device/authorize returns this URL (with the user_code) as verification_uri/verification_uri_complete instead of the built-in managed device page. Lets a CLI surface the project's own RFC 8628 approval page. Empty falls back to the managed page. example: https://app.acme.com/device required: - password_policy AuthInsightsInterval: type: string enum: - day - week - month AuthInsightsResponse: type: object additionalProperties: false properties: project_id: type: string format: uuid observed_at: type: string format: date-time window: $ref: '#/components/schemas/AuthInsightsWindow' summary: $ref: '#/components/schemas/AuthInsightsSummary' series: type: array items: $ref: '#/components/schemas/AuthInsightsSeriesPoint' required: - project_id - observed_at - window - summary - series AuthInsightsSeriesPoint: type: object additionalProperties: false properties: bucket_start: type: string format: date signups: type: integer format: int64 minimum: 0 description: Accounts created during the bucket. signins: type: integer format: int64 minimum: 0 description: Successful session creations during the bucket. is_partial: type: boolean description: Whether the requested window or observation time clips this bucket. required: - bucket_start - signups - signins - is_partial AuthInsightsSummary: type: object additionalProperties: false properties: total_users: type: integer format: int64 minimum: 0 description: Current auth-user count, matching the auth-user list total. active_users_30d: type: integer format: int64 minimum: 0 description: Users with a successful session creation or refresh in the trailing 30 days since activity collection was deployed. required: - total_users - active_users_30d AuthInsightsWindow: type: object additionalProperties: false properties: from: type: string format: date to: type: string format: date interval: $ref: '#/components/schemas/AuthInsightsInterval' required: - from - to - interval AuthHostedPage: type: object properties: id: type: string format: uuid project_id: type: string format: uuid page_type: $ref: '#/components/schemas/HostedAuthPageType' html: type: string description: HTML content for this page type. css: type: string description: CSS content for this page type. created_at: type: string format: date-time updated_at: type: string format: date-time AuthPageAppearanceResponse: type: object required: - theme - layouts - customisation_allowed - parked - defaults - options properties: theme: $ref: '#/components/schemas/AuthPageTheme' layouts: type: object additionalProperties: $ref: '#/components/schemas/AuthPageLayout' customisation_allowed: type: boolean parked: type: object additionalProperties: type: boolean description: Per-page saved-but-not-live state. defaults: $ref: '#/components/schemas/AuthPageAppearanceDefaults' options: $ref: '#/components/schemas/AuthPageAppearanceOptions' AuthPageDensity: type: string enum: - compact - comfortable - spacious AuthPageFont: type: string enum: - system - humanist - geometric - slab - mono AuthPageLayout: type: string enum: - centered - split-left - split-right AuthPageRadius: type: string enum: - none - small - medium - large AuthPageScale: type: string enum: - small - default - large AuthPageTheme: type: object additionalProperties: false required: - version - colors - font - scale - density - radius properties: version: type: integer enum: - 1 colors: $ref: '#/components/schemas/AuthPageThemeColors' font: $ref: '#/components/schemas/AuthPageFont' scale: $ref: '#/components/schemas/AuthPageScale' density: $ref: '#/components/schemas/AuthPageDensity' radius: $ref: '#/components/schemas/AuthPageRadius' AuthHostedPageResponse: type: object required: - page - defaults - runtime properties: page: allOf: - $ref: '#/components/schemas/AuthHostedPage' nullable: true description: The saved page, or null when the project has not customized this page type yet. defaults: $ref: '#/components/schemas/AuthHostedPageDefaults' runtime: $ref: '#/components/schemas/AuthHostedPageRuntime' AuthIdentity: type: object description: | A real email identity owned by the account. One account can own multiple identities (for example a work email plus a personal email linked via OAuth). properties: id: type: string format: uuid description: Unique identity identifier email: type: string format: email description: The email address this identity represents email_verified: type: boolean description: Whether ownership of this email has been verified is_primary: type: boolean description: Whether the account's primary sign-in method resolves to this identity created_at: type: string format: date-time required: - id - email - email_verified - is_primary - created_at AuthIdentitiesResponse: type: object properties: identities: type: array items: $ref: '#/components/schemas/AuthIdentity' required: - identities AuthMethodSummary: type: object description: | A single sign-in method the account owns (password, an OAuth provider, or an active anonymous method). `is_primary` reflects the account's primary_method_id. properties: id: type: string format: uuid description: Unique method identifier type: type: string x-go-type: string description: The kind of sign-in method enum: - password - oauth - anonymous provider: type: string description: OAuth provider name; present only when type is oauth example: google identity_id: type: string description: | The identity this method signs in to — a UUID for password/oauth methods, empty for anonymous methods. email: type: string description: The email of the method's identity (empty for anonymous) is_primary: type: boolean description: Whether this is the account's primary sign-in method last_used_at: type: string format: date-time description: When this method was last used to sign in, if ever created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - type - identity_id - email - is_primary - created_at - updated_at AuthMethodsResponse: type: object properties: methods: type: array items: $ref: '#/components/schemas/AuthMethodSummary' required: - methods AuthPasswordPolicy: type: object additionalProperties: false description: Effective backend-enforced password policy. properties: effective_min_length: type: integer minimum: 15 maximum: 128 description: Effective minimum password length in Unicode characters. min_configurable_length: type: integer minimum: 15 maximum: 15 description: Lowest minimum password length accepted by the auth configuration endpoint. max_length: type: integer minimum: 128 maximum: 128 description: Maximum password length in Unicode characters. require_uppercase: type: boolean description: Whether passwords must contain an ASCII uppercase letter (A-Z). require_lowercase: type: boolean description: Whether passwords must contain an ASCII lowercase letter (a-z). require_numbers: type: boolean description: Whether passwords must contain an ASCII digit (0-9). require_special_chars: type: boolean description: Whether passwords must contain one of the backend-supported special characters. compromised_passwords_rejected: type: boolean description: Whether common and known-compromised passwords are rejected by the backend. required: - effective_min_length - min_configurable_length - max_length - require_uppercase - require_lowercase - require_numbers - require_special_chars - compromised_passwords_rejected AuthSession: type: object description: An authentication session for a user properties: id: type: string format: uuid description: Unique session identifier user_id: type: string format: uuid description: The user this session belongs to provider: type: string description: Authentication provider used to create this session enum: - email - google - github - microsoft - apple - anonymous example: email user_agent: type: string description: Browser/device user agent string example: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ip_address: type: string description: IP address of the client when the session was created example: 192.168.1.1 last_ip_address: type: string description: IP address of the most recent activity (token refresh) example: 192.168.1.100 expires_at: type: string format: date-time description: When this session expires last_activity_at: type: string format: date-time description: Last activity timestamp session_started_at: type: string format: date-time description: When the session was created is_active: type: boolean description: Whether the session is currently active (not expired) is_current: type: boolean description: Whether this is the session making the current request created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - user_id - provider - expires_at - is_active - is_current AuthSignupResponse: type: object description: | Uniform, session-less response returned by POST /auth/signup. It carries no tokens and no user object, and is identical for a new account and for an already-registered email (anti-enumeration). Clients obtain a session with a subsequent POST /auth/signin. properties: confirmation_required: type: boolean description: | Whether the project requires email confirmation. Reflects project config only (identical for a new and an existing email), so it leaks nothing about account existence. message: type: string description: Human-readable acknowledgement. required: - confirmation_required - message AuthTokenResponse: type: object properties: access_token: type: string description: JWT access token (expires after configured lifetime) token_type: type: string example: bearer expires_in: type: integer description: Access token lifetime in seconds refresh_token: type: string x-go-type-skip-optional-pointer: true description: | Long-lived token for getting new access tokens. Omitted when the request uses eligible HttpOnly cookie session storage. user: $ref: '#/components/schemas/AuthUser' required: - access_token - token_type - expires_in - user AuthUser: type: object properties: id: type: string format: uuid project_id: type: string format: uuid email: type: string format: email email_confirmed: type: boolean user_metadata: type: object additionalProperties: true description: User-editable metadata app_metadata: type: object additionalProperties: true description: Application-controlled metadata (read-only for users) avatar_url: type: string format: uri description: User avatar URL (from OAuth provider or manually set) status: type: string enum: - active - banned - deleted banned_until: type: string format: date-time nullable: true description: When temporary ban expires (null if not banned or permanent) last_sign_in_at: type: string format: date-time created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - email - status BanUserResponse: type: object description: Response when banning a user properties: message: type: string example: User banned until 2026-12-31T23:59:59Z user_id: type: string format: uuid email: type: string format: email status: type: string enum: - banned banned_until: type: string format: date-time nullable: true description: When the ban expires (null for permanent ban) required: - message - user_id - email - status BatchFunctionDeployFailure: type: object properties: name: type: string function_id: type: string format: uuid operation: type: string enum: - deploy - update error: type: string required: - name - error BatchFunctionDeployResponse: type: object properties: batch_id: type: string format: uuid data: type: array description: Functions whose deployment workflows were started successfully items: $ref: '#/components/schemas/Function' failed: type: array description: Functions that failed before their workflow started. Successful functions are left running; failed new functions are deleted and failed updates are rolled back where possible. items: $ref: '#/components/schemas/BatchFunctionDeployFailure' required: - batch_id - data CompleteUploadSessionResponse: type: object description: Response when completing an upload properties: object: $ref: '#/components/schemas/StorageObject' CreateDatabaseBackupRequest: type: object properties: name: type: string description: | Backup name, unique within the database. Names beginning with `volcano-` are reserved for the platform's own snapshots. pattern: ^[a-z0-9][a-z0-9_-]{0,62}$ maxLength: 63 example: before_migration required: - name CreateDatabaseBranchRequest: type: object properties: name: type: string description: Branch name (must be unique within the parent database) pattern: ^[a-z0-9_]+$ maxLength: 64 example: feature_checkout ttl_seconds: type: integer format: int64 minimum: 3600 maximum: 2592000 description: | How long the branch should live, between one hour and 30 days. Defaults to 7 days when omitted. example: 86400 required: - name CreateDatabaseRestoreRequest: type: object description: | Names what to restore. Supply exactly one of `backup_name` or `restore_to`. properties: backup_name: type: string minLength: 1 maxLength: 128 description: | A backup of this database to restore, exactly as returned by the list endpoint. Deliberately looser than the names you can create, like the backup path parameter: a backup made by a schedule is named for you, so restoring one accepts any name a backup can have. example: before_migration restore_to: type: string format: date-time description: | A point in time to restore to, which must fall inside the `restore_window` reported when listing backups. example: '2026-01-15T09:30:00Z' CreateDatabaseRequest: type: object description: | Create a new PostgreSQL database. Volcano automatically sets up: - Auth helpers (auth.uid(), auth.email(), auth.role()) - Database roles (anon for unauthenticated, authenticated for signed-in users) - Secure multi-tenant isolation - Ready for Row-Level Security properties: name: type: string description: Database name (must be unique within project) pattern: ^[a-z0-9_]+$ maxLength: 64 example: my_database region: type: string description: | Region for database hosting. The accepted values are the regions this environment runs in, so read them from `GET /databases/regions` rather than hardcoding a list. A region the environment does not offer is rejected with 400. example: aws-us-east-1 pg_version: type: string description: PostgreSQL major version example: '16' enum: - '15' - '16' database_type: type: string description: | Compute size tier (optional, defaults to volcano-db-xs). Determines autoscaling limits for the database. enum: - volcano-db-xs - volcano-db-s - volcano-db-m - volcano-db-l - volcano-db-xl - volcano-db-2xl default: volcano-db-xs example: volcano-db-xs required: - name - region - pg_version CreateEmailTemplateRequest: type: object properties: template_type: type: string enum: - welcome - confirmation - password_reset - password_changed description: Type of email template subject: type: string description: Email subject line example: Confirm your email html_body: type: string description: | HTML template body. Available placeholders: - {{.Token}} - The confirmation/reset token - {{.ProjectName}} - The project name - {{.Email}} - User's email address text_body: type: string description: Plain text template body (same placeholders as HTML) required: - template_type - subject - html_body - text_body CreateFrontendCustomDomainRequest: type: object additionalProperties: false properties: domain: type: string maxLength: 253 description: 'Fully-qualified domain name (hostname only, no scheme/path). Managed TLS (`tls.mode: managed`) accepts at most 219 characters; BYOC accepts 253.' example: app.example.com tls: $ref: '#/components/schemas/FrontendCustomDomainTLSConfig' required: - domain - tls CreateFunctionSchedulerRequest: type: object required: - name - schedule properties: name: type: string maxLength: 200 enabled: type: boolean default: true schedule: $ref: '#/components/schemas/ScheduleRequest' payload: type: object additionalProperties: true regions: type: array description: Optional single explicit deployed region. If omitted, the scheduler chooses one deployed region and invokes according to the cron expression. maxItems: 1 items: type: string CreateOAuthConfigRequest: type: object required: - provider properties: provider: type: string enum: - google - github - microsoft - apple - device example: google client_id: type: string example: 123456789.apps.googleusercontent.com description: Required for non-device providers. Must not be provided for `provider=device`; server always auto-generates it. client_secret: type: string example: GOCSPX-abc123def456 description: Required for non-device providers. Must not be provided for `provider=device`; server always auto-generates it. redirect_url: type: string description: Required for non-device providers. Not used for `provider=device`. format: uri example: https://yourapp.com/auth/callback scopes: type: array items: type: string example: - openid - email - profile description: Optional for non-device providers, uses provider defaults if omitted. Not used for `provider=device`. CreateProjectRequest: type: object description: Request to create a new project properties: name: type: string description: | Project name (must be unique). Can only contain letters, numbers, underscores, and hyphens. pattern: ^[A-Za-z0-9_-]+$ minLength: 1 maxLength: 255 example: my-awesome-app all_regions: type: boolean description: | Optional region policy. - `true` (default): project functions deploy to all configured regions - `false`: project deploys only to `selected_regions` default: true selected_regions: type: array items: type: string description: | Optional region subset. Requires `all_regions=false`. Region names must be a subset of platform `AWS_REGIONS`. example: - us-east-1 - us-west-2 required: - name CreateStorageBucketRequest: type: object properties: name: type: string description: Bucket name (alphanumeric, dashes, underscores) pattern: ^[a-zA-Z0-9_-]+$ minLength: 1 maxLength: 64 file_size_limit: type: integer format: int64 description: Maximum file size in bytes allowed_mime_types: type: array items: type: string description: Allowed MIME types (e.g., ["image/png", "image/jpeg"]) required: - name CreateStoragePolicyRequest: type: object properties: name: type: string description: Policy name operation: type: string enum: - SELECT - INSERT - UPDATE - DELETE description: Operation this policy applies to definition: type: string description: Policy expression required: - name - operation - definition CreateUploadSessionRequest: type: object description: Request to create a resumable upload session properties: object_path: type: string description: Target file path within the bucket example: videos/large-file.mp4 content_type: type: string description: MIME type of the file example: video/mp4 total_size: type: integer format: int64 description: Total file size in bytes (max 5TB) minimum: 1 maximum: 5497558138880 example: 5368709120 part_size: type: integer format: int64 description: 'Part size in bytes (default: 25MB, min: 5MB, max: 25MB)' minimum: 5242880 maximum: 26214400 example: 26214400 required: - object_path - content_type - total_size CreateUploadSessionResponse: type: object description: Response when creating an upload session properties: session_id: type: string description: Upload session ID example: session-abc123 part_size: type: integer format: int64 description: Actual part size to use example: 26214400 total_parts: type: integer description: Number of parts to upload example: 52 expires_at: type: string format: date-time description: When the session expires (7 days from creation) example: '2024-01-22T10:30:00Z' CreateVariableRequest: type: object properties: shared: type: boolean description: Include this name in the project's shared function variables. Omission preserves existing membership; new variables default to true for legacy clients. Send false explicitly to create a non-shared variable. name: type: string minLength: 1 maxLength: 256 pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ value: type: string required: - name - value Database: type: object description: | PostgreSQL database with automatic scalability and security features. properties: id: type: string format: uuid project_id: type: string format: uuid name: type: string description: Database name pattern: ^[a-z0-9_]+$ maxLength: 64 status: type: string enum: - provisioning - active - failed - restoring - deleting description: | Database status. `restoring` means a restore is replacing the database's data: it does not accept connections, and the operations that would race the restore are rejected until it finishes. Its branches keep serving throughout. provisioning_started_at: type: string format: date-time description: Timestamp when the current provisioning phase started connection_string: type: string description: | Secure PostgreSQL connection URI for your database. The database is identified by the globally-unique username (`volcano_client_{database_id}`) already in this URI; the `application_name` parameter only selects the access mode: - `volcano_full_access` — Full admin access (DDL, migrations) - `volcano_user_access:{user_id}` — User impersonation (RLS enforced) - `volcano_user_access` — Anonymous access (anon role, RLS enforced) region: type: string description: Region where the database is hosted example: aws-us-east-1 pg_version: type: string description: PostgreSQL major version example: '16' database_type: type: string description: | Database size tier that determines available RAM and scaling limits. enum: - volcano-db-xs - volcano-db-s - volcano-db-m - volcano-db-l - volcano-db-xl - volcano-db-2xl example: volcano-db-xs storage_bytes: type: integer format: int64 minimum: 0 description: | Latest observed storage for this database, in bytes: its own on-disk size, plus what each branch has diverged from it, plus what its backups cost to hold. This is the figure the storage allowance is enforced against, and the stats endpoint breaks it down. A point-in-time gauge recorded by a background pass, so it may be absent until the database has been sampled, and it can trail the stats endpoint's `current_storage_bytes`, which measures on request. Summing the latest samples for every database in a project produces the project's "Database Storage (Bytes)" usage gauge. Populated on database list responses; single-database responses omit it. last_invoked_at: type: string format: date-time description: Most recent request timestamp for this database created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - project_id - name - status - created_at - updated_at DatabaseBackup: type: object description: | A point-in-time copy of a database, kept by the storage provider and restorable in place. Backups cover the database itself, not its branches. Restoring one replaces the database's data and keeps its connection string. properties: name: type: string description: | Backup name, unique within the database. Backups you create are named by you; scheduled backups are named by the storage provider. source: type: string enum: - manual - scheduled description: | Whether the backup was requested explicitly or produced by the backup schedule. Only `manual` backups count against the plan's backup allowance. size_bytes: type: integer format: int64 minimum: 0 description: | Storage the backup occupies. Absent until the provider has costed it, which takes a few minutes after the backup is taken; absent is not the same as empty. expires_at: type: string format: date-time description: | When the backup is deleted automatically, from the plan's retention. Absent means it is kept until deleted explicitly. created_at: type: string format: date-time description: The point in time the backup captures. required: - name - source - created_at DatabaseBackupList: type: object properties: data: type: array items: $ref: '#/components/schemas/DatabaseBackup' restore_window: $ref: '#/components/schemas/DatabaseRestoreWindow' required: - data DatabaseBackupSchedule: type: object description: | The database's automated backup schedule. An empty list means no scheduled backups; sending one clears the schedule. properties: entries: type: array items: $ref: '#/components/schemas/DatabaseBackupScheduleEntry' required: - entries DatabaseBackupScheduleEntry: type: object description: One recurrence of the automated backup schedule. properties: frequency: type: string enum: - daily - weekly - monthly hour: type: integer minimum: 0 maximum: 23 description: Hour of the day in UTC. day: type: integer minimum: 1 maximum: 28 description: | Day of the week (1-7, Monday to Sunday) for a weekly schedule, or day of the month (1-28) for a monthly one. Required for both, ignored for a daily schedule. Monthly stops at 28 so the schedule fires in every month. retention_seconds: type: integer format: int64 minimum: 3600 description: | How long each backup from this recurrence is kept. Clamped to the plan's retention, and defaulted to it when omitted. required: - frequency - hour DatabaseBranch: type: object description: | A copy-on-write fork of a database, for development and testing. A branch starts as an exact copy of its parent's data and diverges from there. It has its own connection string and its own credential, so a branch password cannot reach the parent. Every branch expires. `expires_at` is a hard deadline: once it passes the branch stops accepting connections and is deleted. Use `PATCH` to extend a branch you are still working on. properties: id: type: string format: uuid database_id: type: string format: uuid description: The parent database this branch was forked from. project_id: type: string format: uuid name: type: string description: Branch name, unique within the parent database. pattern: ^[a-z0-9_]+$ maxLength: 64 status: type: string enum: - provisioning - active - failed - deleting description: | Branch status. A new branch starts `provisioning` and is not connectable until it reports `active`; poll this endpoint until it does. `connection_string` is only present while `active`. `provisioning` also covers a branch being rebuilt after a `reset`, and a build that is between retries, so it is the status to keep waiting on. `failed` is terminal: it means the platform gave up, and the branch will not become `active` on its own. connection_string: type: string description: | PostgreSQL connection URI for this branch. Present only while the branch is `active`. The URI carries the branch's own globally-unique username and password; `application_name` selects the access mode exactly as it does for the parent database: - `volcano_full_access` — Full admin access (DDL, migrations) - `volcano_user_access:{user_id}` — User impersonation (RLS enforced) - `volcano_user_access` — Anonymous access (anon role, RLS enforced) ttl_seconds: type: integer format: int64 minimum: 1 description: | The lifetime the branch was created with. Resetting a branch re-arms this same duration, so a reset never shortens a branch's remaining life. expires_at: type: string format: date-time description: | When the branch stops serving connections and becomes eligible for deletion. Enforced on the connection path, so it holds even if reclamation is delayed. storage_bytes: type: integer format: int64 minimum: 0 description: | Bytes this branch has diverged from its parent, which is what a branch actually costs. Shared pages are not counted twice. Counts against the parent database's storage allowance. Absent until the branch has been sampled. last_invoked_at: type: string format: date-time description: Most recent request timestamp for this branch created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - database_id - project_id - name - status - ttl_seconds - expires_at - created_at - updated_at DatabaseBranchList: type: object properties: data: type: array items: $ref: '#/components/schemas/DatabaseBranch' required: - data DatabaseBranchStorage: type: object description: One branch's contribution to its parent database's storage. properties: id: type: string format: uuid name: type: string description: Branch name storage_bytes: type: integer format: int64 minimum: 0 description: | Bytes this branch has diverged from its parent. Pages the branch still shares with the parent are not counted, so this is what the branch actually adds to the total rather than its apparent size. required: - id - name - storage_bytes DatabaseSelectRequest: type: object properties: table: type: string description: Table name to query example: posts select: type: array items: type: string description: Columns to select (omit for *) example: - id - title - content - created_at filters: type: array items: $ref: '#/components/schemas/DatabaseQueryFilter' description: WHERE conditions (combined with AND) example: - column: status operator: eq value: published - column: views operator: gt value: 100 order: type: array items: $ref: '#/components/schemas/DatabaseQueryOrder' description: ORDER BY clauses example: - column: created_at ascending: false limit: type: integer minimum: 1 maximum: 1000 description: Maximum rows to return example: 10 offset: type: integer minimum: 0 description: Number of rows to skip (for pagination) example: 0 required: - table DatabaseInsertRequest: type: object properties: table: type: string description: Table name example: posts values: type: object additionalProperties: true description: Column values to insert example: title: My New Post content: This is the content status: draft required: - table - values DatabaseUpdateRequest: type: object properties: table: type: string description: Table name example: posts values: type: object additionalProperties: true description: Column values to update example: title: Updated Title status: published filters: type: array minItems: 1 items: $ref: '#/components/schemas/DatabaseQueryFilter' description: | WHERE conditions for which rows to update. At least one filter is required; a filterless update is rejected to avoid rewriting every row. example: - column: id operator: eq value: post-uuid required: - table - values - filters DatabaseDeleteRequest: type: object properties: table: type: string description: Table name example: posts filters: type: array minItems: 1 items: $ref: '#/components/schemas/DatabaseQueryFilter' description: WHERE conditions (required for safety) example: - column: id operator: eq value: post-uuid required: - table - filters DatabaseQueryResult: type: object description: | Rows returned by a data API request. RLS-filtered unless the request was made with a service key. properties: data: type: array items: type: object additionalProperties: true description: Result rows count: type: integer description: Number of rows returned DatabaseRestore: type: object description: | A restore of a database, either from a named backup or to a point in time. Restores run in the background and take longer than a request, so the database is unavailable until this reports `completed`. properties: id: type: string format: uuid database_id: type: string format: uuid project_id: type: string format: uuid kind: type: string enum: - snapshot - point_in_time description: | Whether the restore targets a named backup or an arbitrary point in time. Both replace the database's data in place. status: type: string enum: - pending - running - completed - failed - exhausted description: | Restore status. `pending` and `running` both mean the restore is still in flight and the database is not connectable; an attempt that fails with tries left goes back to `pending`. `failed` and `exhausted` both mean Volcano gave up: the database is left `failed` if its data may already have been replaced, and `active` if the restore never started — a backup that no longer exists at the provider ends the restore without touching the database. A restore cannot be cancelled once it starts. backup_name: type: string description: | The backup restored, kept even if that backup is later deleted. Absent for a point-in-time restore. restore_to: type: string format: date-time description: The point in time restored to. Absent for a backup restore. error: type: string description: Why the most recent attempt failed, when one has. completed_at: type: string format: date-time created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - database_id - project_id - kind - status - created_at - updated_at DatabaseRestoreList: type: object properties: data: type: array items: $ref: '#/components/schemas/DatabaseRestore' required: - data DatabaseRestoreWindow: type: object description: | The span a point-in-time restore may target. Absent from the response when the owner's plan does not include point-in-time restore, and while the storage provider has no history window in place yet — briefly the case after an upgrade, since the window is applied asynchronously. The window is read from the provider rather than from the plan, so it never advertises a point a restore could not actually reach. properties: earliest_restore_at: type: string format: date-time description: | The oldest point that can still be restored. Moves forward continuously as history ages out, so treat it as a lower bound at the moment it was read rather than a fixed value. latest_restore_at: type: string format: date-time description: The most recent point that can be restored, which is now. DatabaseStats: type: object properties: current_storage_bytes: type: integer format: int64 minimum: 0 description: | On-disk size right now, in bytes: the database itself, plus every branch's divergence from it, plus what its backups cost to hold. This is the figure the storage allowance is enforced against. `branches` and `backup_storage_bytes` break it down. current_storage_mb: type: number format: double minimum: 0 description: '`current_storage_bytes` expressed in megabytes.' branches: type: array description: | Per-branch contribution to `current_storage_bytes`. Empty when the database has no branches. A branch that has not diverged from its parent contributes nothing. items: $ref: '#/components/schemas/DatabaseBranchStorage' backup_storage_bytes: type: integer format: int64 minimum: 0 description: | What this database's backups contribute to `current_storage_bytes`. A backup taken on request is charged as a full copy of the database as it was at that moment, so two backups of a 2 GB database are 4 GB. A backup schedule is charged its first snapshot in full and each later one only for the storage it adds. Deleting a backup releases its storage immediately. Sampled from the provider rather than measured live, so it can lag a change by a few minutes, and a backup taken seconds ago may not be costed yet. Zero on a plan without backups. storage_bytes: type: integer format: int64 description: Total storage used in bytes (data + WAL) data_written_bytes: type: integer format: int64 description: Total data written in bytes data_transfer_bytes: type: integer format: int64 description: Total data transferred in bytes compute_time_seconds: type: number format: double description: Total CPU seconds consumed active_time_seconds: type: number format: double description: Total active compute time in seconds time_range: type: string description: Time range of the metrics (e.g., "2024-01-01T00:00:00Z to 2024-01-02T00:00:00Z") granularity: type: string enum: - hourly - daily - monthly description: Granularity of the aggregated metrics required: - current_storage_bytes - current_storage_mb - backup_storage_bytes - storage_bytes - data_written_bytes - data_transfer_bytes - compute_time_seconds - active_time_seconds DatabaseQueryPerformanceResponse: type: object properties: data: type: array items: $ref: '#/components/schemas/DatabaseQueryPerformanceItem' required: - data UpdateDatabaseBranchRequest: type: object description: Replace the branch's lifetime and restart its countdown from now. properties: ttl_seconds: type: integer format: int64 minimum: 3600 maximum: 2592000 description: The new lifetime, between one hour and 30 days. example: 86400 required: - ttl_seconds DeviceAuthorizationResponse: type: object properties: device_code: type: string user_code: type: string verification_uri: type: string description: | Browser verification URL. Points at the project's managed device approval page served by this API: `/projects/{projectId}/auth/hosted?action=device&anon_key=...`. Requires the project to have managed auth enabled and a default anon key. A custom CLI may ignore this and direct users to its own RFC 8628-compatible page instead (see the device-auth guide). verification_uri_complete: type: string description: | Same as `verification_uri` but with the `user_code` prefilled (`&user_code=...`). This is the URL most device clients open. expires_in: type: integer interval: type: integer required: - device_code - user_code - verification_uri - verification_uri_complete - expires_in - interval EmailTemplate: type: object description: Custom email template properties: id: type: string format: uuid project_id: type: string format: uuid template_type: type: string enum: - welcome - confirmation - password_reset - password_changed subject: type: string example: Confirm your email address html_body: type: string description: HTML template with placeholders text_body: type: string description: Plain text template with placeholders created_at: type: string format: date-time updated_at: type: string format: date-time required: - template_type - subject - html_body - text_body Error: type: object properties: error: type: string code: type: string description: Stable machine-readable error code when a specific recovery path is available. required: - error ImportProvider: type: string enum: - vercel default: vercel x-enum-varnames: - ImportProviderVercel ImportConnectStartResponse: type: object properties: authorization_url: type: string required: - authorization_url ImportConnection: type: object properties: id: type: string format: uuid provider: $ref: '#/components/schemas/ImportProvider' account_id: type: string account_name: type: string configuration_id: type: string granted_scopes: type: array items: type: string status: type: string expires_at: type: string format: date-time nullable: true last_authenticated_at: type: string format: date-time created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - provider - account_id - account_name - configuration_id - granted_scopes - status - last_authenticated_at - created_at - updated_at ImportConnectionsResponse: type: object properties: connections: type: array items: $ref: '#/components/schemas/ImportConnection' required: - connections ImportSource: type: object properties: id: type: string name: type: string account_id: type: string framework: type: string required: - id - name - account_id - framework ImportSourcesResponse: type: object properties: sources: type: array items: $ref: '#/components/schemas/ImportSource' required: - sources ProjectImportTarget: type: string enum: - production x-enum-varnames: - ProjectImportTargetProduction ProjectImportDestinationMode: type: string enum: - create x-enum-varnames: - ProjectImportDestinationCreate ProjectImportDisposition: type: string enum: - automatic - manual - deferred - unsupported x-enum-varnames: - ProjectImportDispositionAutomatic - ProjectImportDispositionManual - ProjectImportDispositionDeferred - ProjectImportDispositionUnsupported ProjectImportImpact: type: string enum: - none - warning - blocking x-enum-varnames: - ProjectImportImpactNone - ProjectImportImpactWarning - ProjectImportImpactBlocking ProjectImportReadiness: type: string enum: - importable - needs_input - blocked x-enum-varnames: - ProjectImportReadinessImportable - ProjectImportReadinessNeedsInput - ProjectImportReadinessBlocked ProjectImportActionCode: type: string enum: - project.create - git.connect - frontend.configure - variable.set x-enum-varnames: - ProjectImportActionProjectCreate - ProjectImportActionGitConnect - ProjectImportActionFrontendConfigure - ProjectImportActionVariableSet ProjectImportResourceKind: type: string enum: - project - git_repository - frontend - variable - domain x-enum-varnames: - ProjectImportResourceProject - ProjectImportResourceGitRepository - ProjectImportResourceFrontend - ProjectImportResourceVariable - ProjectImportResourceDomain ProjectImportPreflightRequest: type: object properties: connection_id: type: string format: uuid source_id: type: string minLength: 1 project_name: type: string maxLength: 255 pattern: ^[A-Za-z0-9_-]+$ target: $ref: '#/components/schemas/ProjectImportTarget' confirm_environment_variable_read: type: boolean default: false description: Set to true only after the user confirms an immediately preceding disclosure that the Vercel Integration grant permits reads and writes, while this preflight reads production variable values only. When false or omitted, preflight reads variable metadata only and reports readable values as manual input. required: - connection_id - source_id - project_name - target ProjectImportStartRequest: type: object properties: connection_id: type: string format: uuid source_id: type: string minLength: 1 maxLength: 255 project_name: type: string maxLength: 255 pattern: ^[A-Za-z0-9_-]+$ target: $ref: '#/components/schemas/ProjectImportTarget' confirm_environment_variable_read: type: boolean enum: - true preflight_fingerprint: type: string pattern: ^sha256:[0-9a-f]{64}$ required: - connection_id - source_id - project_name - target - confirm_environment_variable_read - preflight_fingerprint ProjectImportRunStatus: type: string enum: - pending - running - succeeded - failed - superseded x-enum-varnames: - ProjectImportRunStatusPending - ProjectImportRunStatusRunning - ProjectImportRunStatusSucceeded - ProjectImportRunStatusFailed - ProjectImportRunStatusSuperseded ProjectImportRun: type: object properties: id: type: string provider: $ref: '#/components/schemas/ImportProvider' source_id: type: string destination_project_name: type: string resource: $ref: '#/components/schemas/ResourceReference' deployment: $ref: '#/components/schemas/DeploymentReference' status: $ref: '#/components/schemas/ProjectImportRunStatus' error_code: type: string error_message: type: string created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - provider - source_id - destination_project_name - resource - deployment - status - created_at - updated_at ProjectImportDestination: type: object properties: mode: $ref: '#/components/schemas/ProjectImportDestinationMode' project_name: type: string target: $ref: '#/components/schemas/ProjectImportTarget' required: - mode - project_name - target ProjectImportResource: type: object properties: kind: $ref: '#/components/schemas/ProjectImportResourceKind' name: type: string source_id: type: string minLength: 1 description: Stable provider identifier for a scoped source resource. scope: type: string minLength: 1 description: URL-encoded source scope, including target, branch, and custom environment identifiers. required: - kind - name ProjectImportAction: type: object properties: code: $ref: '#/components/schemas/ProjectImportActionCode' resource: $ref: '#/components/schemas/ProjectImportResource' disposition: $ref: '#/components/schemas/ProjectImportDisposition' required: - code - resource - disposition ProjectImportFinding: type: object properties: code: type: string pattern: ^(vercel|volcano|import)\.[a-z0-9_]+$ resource: $ref: '#/components/schemas/ProjectImportResource' disposition: $ref: '#/components/schemas/ProjectImportDisposition' impact: $ref: '#/components/schemas/ProjectImportImpact' message: type: string remediation: type: string required: - code - resource - disposition - impact - message - remediation ProjectImportSummary: type: object properties: automatic: type: integer minimum: 0 manual: type: integer minimum: 0 deferred: type: integer minimum: 0 unsupported: type: integer minimum: 0 warnings: type: integer minimum: 0 blocking: type: integer minimum: 0 required: - automatic - manual - deferred - unsupported - warnings - blocking ProjectImportReport: type: object properties: schema_version: type: string provider: $ref: '#/components/schemas/ImportProvider' source: $ref: '#/components/schemas/ImportSource' destination: $ref: '#/components/schemas/ProjectImportDestination' actions: type: array items: $ref: '#/components/schemas/ProjectImportAction' findings: type: array items: $ref: '#/components/schemas/ProjectImportFinding' summary: $ref: '#/components/schemas/ProjectImportSummary' readiness: $ref: '#/components/schemas/ProjectImportReadiness' source_fingerprint: type: string capability_fingerprint: type: string fingerprint: type: string generated_at: type: string format: date-time required: - schema_version - provider - source - destination - actions - findings - summary - readiness - source_fingerprint - capability_fingerprint - fingerprint - generated_at GitConnection: type: object properties: id: type: string format: uuid provider: type: string provider_user_id: type: string provider_login: type: string status: type: string last_authenticated_at: type: string format: date-time created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - provider - provider_user_id - provider_login - status - last_authenticated_at - created_at - updated_at GitConnectStartResponse: type: object properties: authorization_url: type: string required: - authorization_url GitConnectionsResponse: type: object properties: connections: type: array items: $ref: '#/components/schemas/GitConnection' required: - connections GitInstallation: type: object properties: id: type: integer format: int64 account_login: type: string account_type: type: string repository_selection: type: string required: - id - account_login - account_type - repository_selection GitInstallationsResponse: type: object properties: installations: type: array items: $ref: '#/components/schemas/GitInstallation' required: - installations GitRepository: type: object properties: id: type: integer format: int64 description: Stable GitHub repository id (repository.id), unchanged by renames. full_name: type: string default_branch: type: string private: type: boolean is_empty: type: boolean description: Whether the repository has no commits and can receive an initial source export. required: - id - full_name - default_branch - private - is_empty GitRepositoriesResponse: type: object properties: repositories: type: array items: $ref: '#/components/schemas/GitRepository' required: - repositories ProjectGitConnection: type: object properties: repo_installation_id: type: integer format: int64 repo_id: type: integer format: int64 description: Stable GitHub repository id (repository.id), the authoritative binding. repo_full_name: type: string root_directory: type: string production_branch: type: string description: The branch a push must land on to deploy. Follows the repository's GitHub default branch unless the project set its own, which a default-branch rename on GitHub then leaves alone. updated_at: type: string format: date-time required: - repo_installation_id - repo_id - repo_full_name - root_directory - production_branch - updated_at ProjectGitDeploySettings: type: object description: 'A project''s GitHub auto-deploy settings: what a push to the connected repo''s production branch deploys. All settings are default-off.' properties: auto_deploy_enabled: type: boolean description: Whether a production-branch push triggers a deployment. deploy_functions: type: boolean description: Whether the repo's functions are deployed on push. frontend_name: type: string description: Name of the frontend to build and deploy on push. Omitted when no frontend is deployed. Resolved at deploy time; need not exist yet. frontend_app_root: type: string description: App root (subdirectory) the frontend builds from. Omitted for the repo root. updated_at: type: string format: date-time required: - auto_deploy_enabled - deploy_functions - updated_at UpdateProjectGitDeploySettingsRequest: type: object description: Full replace of a project's Git auto-deploy settings. properties: auto_deploy_enabled: type: boolean deploy_functions: type: boolean frontend_name: type: string description: Frontend to deploy on push. Omit or empty to deploy no frontend. frontend_app_root: type: string description: App root the frontend builds from. Requires frontend_name; omit for the repo root. required: - auto_deploy_enabled - deploy_functions ProjectLockLeaseRequest: type: object additionalProperties: false properties: ttl_seconds: type: integer minimum: 5 maximum: 7776000 description: | Lease duration in seconds, from 5 seconds through 90 days, measured from when the request is served. Renew before it elapses. A renewal sets the new expiry outright, so a shorter TTL shortens the lease. Renewals cannot extend an acquisition beyond its absolute 90-day deadline. required: - ttl_seconds ProjectLockLease: type: object additionalProperties: false properties: expires_at: type: string format: date-time description: Advisory lease expiry timestamp in UTC. fencing_token: type: integer format: int64 description: | Monotonically increasing token for this acquisition. It rises whenever the lock changes hands and stays the same across renewals of one lease. Pass it to the resource you are protecting and reject any write carrying a token lower than the highest already seen; that is what stops a displaced holder from writing after its lease lapsed. required: - expires_at - fencing_token ProjectLockState: type: object additionalProperties: false properties: held: type: boolean description: | Whether the lock is unavailable right now. False means an acquire would succeed. It remains true during the brief grace window after expiry. expires_at: type: string format: date-time description: Advisory lease expiry timestamp in UTC. Present only when held. fencing_token: type: integer format: int64 description: Current holder's fencing token. Present only when held. required: - held ProjectSourceExportState: type: object description: The project's source of truth and any pending Git transition. properties: mode: type: string enum: - platform - git_exporting - git_pending - git transition_started_at: type: string format: date-time nullable: true description: When source export started, cleared if an incomplete transition is canceled. exported_at: type: string format: date-time nullable: true description: When the initial export push entered deployment, or when a transition was canceled after its commit was reserved. Once set, the one-time export is consumed. handed_over_at: type: string format: date-time nullable: true description: When a complete production-branch deployment first proved the repository could drive the project, null until then. Once set, the repository is the project's source of truth. required: - mode - transition_started_at - exported_at - handed_over_at ProjectSourceExport: type: object description: The initial production-branch commit, and everything export could not carry. properties: repo_full_name: type: string branch: type: string description: The production branch that was created. commit_sha: type: string file_count: type: integer skipped: type: array description: Resources whose source could not be taken, with the reason. Most often a resource that has never deployed successfully. items: $ref: '#/components/schemas/ProjectSourceExportSkip' omitted: type: array description: Things deliberately left out of the branch. items: $ref: '#/components/schemas/ProjectSourceExportOmission' required: - repo_full_name - branch - commit_sha - file_count - skipped - omitted ExportProjectSourceRequest: type: object additionalProperties: false properties: production_branch: type: string minLength: 1 description: The currently configured production branch the user confirmed for export. required: - production_branch ProjectSourceExportSkip: type: object properties: kind: type: string description: 'The kind of resource, "function" or "frontend". Deliberately not an enum: the generated constants would collide with an existing resource-type enum and rename its members.' name: type: string reason: type: string required: - kind - name - reason ProjectSourceExportOmission: type: object properties: kind: type: string description: 'What was left out: migrations Volcano stores no copy of, variable values, a credential-shaped file, installed dependencies, or an archive entry a repository cannot carry.' resource: type: string description: The resource it came from, empty when project-wide. path: type: string required: - kind - resource - path SetProjectGitProductionBranchRequest: type: object properties: production_branch: type: string minLength: 1 maxLength: 255 description: The branch a push must land on to deploy. Validated as a Git branch name only — it does not have to exist yet. required: - production_branch ConnectProjectGitRequest: type: object properties: connection_id: type: string format: uuid description: The caller's user_git_connections row (see /user/git/connections). installation_id: type: integer format: int64 repository_id: type: integer format: int64 description: Stable GitHub repository id (repository.id), the preferred selector. Either repository_id or repo_full_name is required; when both are given they must identify the same live repository. repo_full_name: type: string deprecated: true description: Deprecated selector kept for a compatibility window; prefer repository_id. Either repository_id or repo_full_name is required. root_directory: type: string description: Monorepo subdirectory the project builds from. Omit for the repo root. production_branch: type: string maxLength: 255 description: 'The branch a push must land on to deploy, with three cases, because this is a full replace and a read-modify-write client sends back whatever it read. Omit it to follow the repository''s GitHub default branch, which also discards a branch set earlier. Send back the branch the project already deploys from, when that is the repository''s default, and nothing changes either way — a project pinned to that branch stays pinned. Sending the default branch when the project deploys from something else returns it to following the default, including on a rebind, where a pin describes a branch chosen for the repository being left. Any other branch becomes the project''s own choice, exempt from later default-branch renames. Validated as a Git branch name only: it does not have to exist yet, so a project can be pointed at a branch about to be pushed. Changing repository and naming a branch other than the new repository''s default in one request is refused with 400, because the branch named is almost always the previous repository''s, echoed back — connect first, then set the branch.' required: - connection_id - installation_id Frontend: type: object properties: id: type: string format: uuid project_id: type: string format: uuid name: type: string maxLength: 63 pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ framework: type: string enum: - nextjs app_root: type: string maxLength: 1024 description: Optional relative POSIX path from the uploaded archive root to the Next.js app that is deployed. status: type: string description: | Frontend lifecycle status. `degraded` means the regional runtime remains available but edge synchronization exhausted its immediate retries; Volcano retries edge recovery without rebuilding the frontend, and stops once a new deployment is queued or the retry budget runs out, leaving the frontend `degraded` until the next redeploy. A redeploy that fails over a serving frontend stays `active` on the previous deployment, so `failed` means no deployment is serving. enum: - provisioning - active - degraded - failed - deleting provisioning_started_at: type: string format: date-time description: Timestamp when the current provisioning phase started deployed_regions: type: array items: type: string current_deployment_id: type: string format: uuid description: Identifier of the latest frontend deployment operation pending_deployment_id: type: string format: uuid description: Newest queued deployment that will run after the current operation site_url: type: string custom_domain: type: string description: Active custom domain hostname when configured custom_domain_status: type: string description: Current custom domain lifecycle status enum: - pending_verification - provisioning - active - detaching - failed - deleted last_invoked_at: type: string format: date-time created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - project_id - name - framework - status - deployed_regions - created_at - updated_at FrontendCustomDomainTLSConfig: type: object description: 'TLS for a new custom domain. With `mode: managed`, Volcano issues and renews the certificate; omit every PEM field. With `mode: byoc`, send both `certificate_pem` and `private_key_pem`, plus an optional `certificate_chain_pem`.' additionalProperties: false not: anyOf: - allOf: - properties: mode: enum: - managed required: - mode - anyOf: - required: - certificate_pem - required: - private_key_pem - required: - certificate_chain_pem - allOf: - properties: mode: enum: - byoc required: - mode - anyOf: - not: required: - certificate_pem - not: required: - private_key_pem properties: mode: type: string enum: - managed - byoc default: byoc description: managed for a Volcano-issued certificate; byoc to supply your own. certificate_pem: type: string maxLength: 65536 description: PEM-encoded certificate. Required when mode is byoc; not allowed when mode is managed. private_key_pem: type: string maxLength: 65536 description: PEM-encoded private key. Required when mode is byoc; not allowed when mode is managed. certificate_chain_pem: type: string maxLength: 65536 description: Optional PEM-encoded certificate chain when mode is byoc; not allowed when mode is managed. required: - mode FrontendCustomDomainResponse: type: object properties: domain: type: string tls_mode: type: string enum: - managed - byoc domain_status: type: string enum: - pending_verification - provisioning - active - detaching - failed - deleted verification_status: type: string enum: - pending - verified - failed description: '`verified`: the domain is served by a validated certificate. `pending`: it is not served yet, is being re-validated after its certificate material was withdrawn, or Volcano is retrying after a failure. `failed`: a failure left the domain unserved, alongside `domain_status: failed`; managed domains report the cause in `failure_reason`.' failure_reason: type: string description: Failure category, present only when managed TLS setup has failed. Current values are provider, certificate, ownership, and internal; ownership means another account has already claimed the hostname through ownership verification. Treat unrecognized values as internal. verification_records: type: array items: $ref: '#/components/schemas/FrontendDomainVerificationRecord' required_routing_record: allOf: - $ref: '#/components/schemas/FrontendDomainRoutingRecord' deprecated: true description: Deprecated and no longer returned. Use routing_target_hostname as the DNS routing target. routing_target_hostname: type: string description: DNS routing target hostname for this frontend. The DNS record type depends on whether the custom domain is a zone apex. effective_urls: type: array items: type: string created_at: type: string format: date-time updated_at: type: string format: date-time required: - domain - tls_mode - domain_status - verification_status - effective_urls - created_at - updated_at FrontendDeployment: type: object properties: id: type: string format: uuid frontend_id: type: string format: uuid project_id: type: string format: uuid operation: type: string enum: - deploy - redeploy - delete status: type: string description: | Deployment lifecycle status. A `degraded` redeploy remains available while edge-only recovery is retried. A `failed` redeploy is recorded here while the frontend keeps serving its previous deployment. enum: - queued - provisioning - active - degraded - failed - superseded - deleting - deleted deploy_source: type: string enum: - git - cli - web - api - system - unknown description: What initiated this deployment. initiated_by: type: string description: Platform user that triggered a request-initiated deployment; absent for git and system deployments. artifact_bucket: type: string artifact_key: type: string artifact_version: type: string site_url: type: string cloudformation_stack_id: type: string cloudformation_stack_url: type: string codebuild_duration_seconds: type: integer format: int64 description: Total CodeBuild build duration recorded for this deployment, in seconds. codebuild_build_count: type: integer description: Number of completed CodeBuild builds included in codebuild_duration_seconds. codebuild_duration_recorded_at: type: string format: date-time progress: $ref: '#/components/schemas/DeploymentProgress' error_message: type: string created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - frontend_id - project_id - operation - status - deploy_source - created_at - updated_at FrontendDomainRoutingRecord: type: object properties: record_type: type: string enum: - CNAME name: type: string value: type: string required: - record_type - name - value FrontendDomainVerificationRecord: type: object description: The DNS records currently required for managed TLS. Volcano may require a tenant-specific TXT ownership record before returning a CNAME that authorizes certificate issuance and renewal. Clients must follow the records returned for the current lifecycle state instead of assuming a fixed sequence. properties: name: type: string type: type: string value: type: string required: - name - type - value FrontendCustomDomainConflictError: description: 'Custom domain create conflict. With `code: ownership_verification_required`, another account holds an unverified managed TLS reservation for the hostname: publish `required_record` in DNS and send the same request again. The retry succeeds once Volcano can see the record. Other conflicts omit both fields.' allOf: - $ref: '#/components/schemas/Error' - type: object properties: required_record: $ref: '#/components/schemas/FrontendDomainVerificationRecord' FrontendUsageDailyEntry: type: object description: One day of request and error counts for a single frontend. properties: day: type: string format: date description: UTC date (YYYY-MM-DD) the counts cover. requests: type: integer format: int64 description: Total requests served on this day. errors: type: integer format: int64 description: 5xx responses served on this day. page_views: type: integer format: int64 description: Navigable-document responses served on this day (text/html or Sec-Fetch-Dest=document) — strict subset of `requests`. required: - day - requests - errors - page_views FrontendUsageData: type: object description: Monthly frontend request totals grouped by frontend. properties: frontend_id: type: string format: uuid description: Frontend ID frontend_name: type: string description: Frontend name at the time usage was fetched nullable: true requests: type: integer format: int64 description: Total requests for this frontend in the current usage month required: - frontend_id - requests FrontendUsageHistoryResponse: type: object description: Zero-filled daily series of request + error counts for a single frontend, oldest first. properties: frontend_id: type: string format: uuid days: type: integer description: Number of daily entries returned (always equal to the `days` query param after clamping). daily: type: array items: $ref: '#/components/schemas/FrontendUsageDailyEntry' total_requests: type: integer format: int64 total_errors: type: integer format: int64 total_page_views: type: integer format: int64 required: - frontend_id - days - daily - total_requests - total_errors - total_page_views Function: type: object properties: id: type: string format: uuid project_id: type: string format: uuid name: type: string maxLength: 63 pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ status: type: string enum: - provisioning - active - failed - deleting provisioning_started_at: type: string format: date-time description: Timestamp when the current provisioning phase started is_public: type: boolean description: | Function visibility for anon-key invocation. - `false` (default): only auth user tokens and service keys can invoke - `true`: anon keys with `functions.invoke` can invoke invocation_mode: $ref: '#/components/schemas/FunctionInvocationMode' http_auth_mode: $ref: '#/components/schemas/FunctionHTTPAuthMode' openapi_spec: type: object nullable: true additionalProperties: true description: Optional OpenAPI 3.0 or 3.1 document describing an HTTP-mode function. has_openapi_spec: type: boolean description: Whether OpenAPI metadata is configured; list responses omit the document itself. aws_function_arn: type: string invoke_url: type: string description: 'Canonical geo-routed HTTPS endpoint for invoking this function. Use it as-is: it does not share a domain with the API, so a host derived from the API URL will not reach the function. Omitted when the deployment serves no public invocation domain, as in local development, so a client testing for an empty string never matches.' deployed_regions: type: array items: type: string description: Regions where this function is currently deployed runtime: type: string handler: type: string current_deployment_id: type: string format: uuid description: Identifier of the latest function deployment operation pending_deployment_id: type: string format: uuid description: Newest queued deployment that will run after the current operation last_invoked_at: type: string format: date-time description: Most recent successful invocation timestamp created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - project_id - name - status - is_public - invocation_mode - http_auth_mode - openapi_spec - has_openapi_spec - deployed_regions - created_at - updated_at DurableFunction: type: object description: | A durable function. Separate from `Function` because a durable function is invoked only through its own execution endpoints, so it has no invocation mode, HTTP auth mode, OpenAPI document or invoke URL, and it carries a `durable` configuration that a standard function has no field for. properties: id: type: string format: uuid project_id: type: string format: uuid name: type: string maxLength: 63 pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ status: type: string enum: - provisioning - active - failed - deleting provisioning_started_at: type: string format: date-time description: Timestamp when the current provisioning phase started is_public: type: boolean description: | Whether anon keys may start executions of this function through `POST /durable-functions/{functionId}/executions`. When `true`, an anon key holding `functions.invoke` can start an execution. When `false` (the default) only service keys and auth user tokens can. Reading and stopping an execution always require the project owner's token, whatever this is set to. Set it when the function is created. Durable functions have no update endpoint, so changing visibility later means redeploying. A public durable function is startable, never invocable: it is not reachable through `POST /functions/{functionId}/invoke` or a function URL, which answer `404` for either visibility. durable: $ref: '#/components/schemas/DurableFunctionConfig' deployed_regions: type: array items: type: string description: Regions where this function is currently deployed runtime: type: string handler: type: string current_deployment_id: type: string format: uuid description: Identifier of the latest deployment operation pending_deployment_id: type: string format: uuid description: Newest queued deployment that will run after the current operation last_invoked_at: type: string format: date-time description: Most recent successful invocation timestamp created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - project_id - name - status - is_public - durable - deployed_regions - created_at - updated_at DurableFunctionConfig: type: object description: | Execution limits the function was created with, derived from the project's plan. Fixed for the life of the function: changing them means creating a new one. The memory the function runs at, and the timeout on one attempt within an execution, also come from the plan but are not reported here: they are applied to the deployed function rather than recorded on it. Both are published per plan in the plans and limits guide. properties: execution_timeout_seconds: type: integer format: int64 description: | How long a whole execution may run, including time suspended in a wait. This is not a limit on one attempt: an execution outlives any single attempt by checkpointing and resuming, and the per-attempt timeout is the plan's own, smaller number. retention_days: type: integer format: int64 description: | How long a finished execution's result and history are retained, for as long as the function exists. Deleting the function, or its project, ends retention early and takes the history with it. required: - execution_timeout_seconds - retention_days DurableExecution: type: object properties: id: type: string format: uuid function_id: type: string format: uuid name: type: string description: | Idempotency key for the execution. Supplied by the client through `X-Volcano-Execution-Name`, otherwise generated. status: $ref: '#/components/schemas/DurableExecutionStatus' region: type: string description: | Region the execution runs in. An execution is pinned to one region for its whole life because its checkpoints live there. result: description: | Whatever the function returned, verbatim. Absent while the execution is still running, absent when the result was too large to return and was checkpointed instead, and absent once the retention period has lapsed. result_expired: type: boolean description: | `true` when the execution is terminal but its result is no longer retained, which distinguishes a discarded result from an empty one. Shortly after that the execution itself is dropped and reads answer `404`. A result that was checkpointed rather than returned leaves this unset, so it reads like a function that returned nothing. error: $ref: '#/components/schemas/DurableExecutionError' created_at: type: string format: date-time completed_at: type: string format: date-time description: Present once the execution has reached a terminal status. required: - id - function_id - name - status - region - created_at DurableExecutionStatus: type: string enum: - pending - running - succeeded - failed - timed_out - stopped - unknown description: | Lifecycle state of an execution. `pending` covers the window between the platform reserving the execution name and the function accepting the start, and has no counterpart once the execution is under way. `succeeded`, `failed`, `timed_out`, `stopped` and `unknown` are terminal. `unknown` means the execution's outcome cannot be established, so no result or error can be given for it. Either it was under way and was never seen to finish, or its start failed with a `500` without the platform establishing whether the execution began — which is why a name whose start returned an error can later read as `unknown` rather than not being found. It is terminal because nothing can settle it later, and it is rare — treat it as an outcome to retry rather than a state to wait on. A retry under the same name picks this execution back up instead of starting a second one, and needs a free concurrency slot because an `unknown` execution has given its own up. `completed_at` on an `unknown` execution is when the platform gave up, not when the work ended. DurableExecutionError: type: object description: Why a failed or timed-out execution ended. properties: type: type: string message: type: string FunctionInvocationMode: type: string enum: - rpc - http description: | Invocation contract. `rpc` preserves the existing POST `{payload: ...}` contract; `http` forwards HTTP request semantics to the function runtime. FunctionHTTPAuthMode: type: string enum: - volcano - none description: | Authentication applied by the HTTP ingress. `none` is valid only for public HTTP-mode functions and is intended for externally signed webhooks. FunctionDeployment: type: object properties: id: type: string format: uuid function_id: type: string format: uuid project_id: type: string format: uuid batch_id: type: string format: uuid operation: type: string enum: - deploy - update - delete status: type: string enum: - queued - provisioning - active - failed - superseded - deleting - deleted deploy_source: type: string enum: - git - cli - web - api - system - unknown description: What initiated this deployment. initiated_by: type: string description: Platform user that triggered a request-initiated deployment; absent for git and system deployments. artifact_bucket: type: string artifact_key: type: string artifact_version: type: string codebuild_duration_seconds: type: integer format: int64 description: Total CodeBuild build duration recorded for this deployment, in seconds. codebuild_build_count: type: integer description: Number of completed CodeBuild builds included in codebuild_duration_seconds. codebuild_duration_recorded_at: type: string format: date-time progress: $ref: '#/components/schemas/DeploymentProgress' error_message: type: string completed_at: type: string format: date-time created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - function_id - project_id - operation - status - deploy_source - created_at - updated_at FunctionInvocationRequest: type: object properties: payload: type: object additionalProperties: true description: | Payload to send to the function. If invoked with auth user token, Volcano automatically injects `__volcano_auth` context: ```javascript { ...yourPayload, __volcano_auth: { user_id: "uuid", email: "user@example.com", project_id: "uuid", role: "authenticated" | "anonymous" } } ``` FunctionInvocationResponse: type: object description: Raw function response body returned by the invoked function. additionalProperties: true LogActivityBucket: type: object description: Log-event counts for one activity time bucket. properties: start_time: type: string format: date-time description: Bucket start time. end_time: type: string format: date-time description: Bucket end time. counts: type: object description: Counts grouped by activity dimension. properties: levels: type: object additionalProperties: type: integer description: Counts by normalized log level. regions: type: object additionalProperties: type: integer description: Counts by event region. resource_ids: type: object additionalProperties: type: integer description: Counts by resource ID. required: - levels - regions - resource_ids total: type: integer description: Total events in this bucket. required: - start_time - end_time - counts - total LogActivityRequest: type: object description: Activity request for bucketed log counts. additionalProperties: false properties: resource: $ref: '#/components/schemas/LogRequestResource' q: type: string maxLength: 512 description: Optional activity query. Supports quoted text, implicit AND, AND/OR/NOT, parentheses, and fields such as `level`, `region`, `invocation.id`, `resource.id`, `resource.name`, `function`, `frontend`, `database`, and `body`. start_time: type: string format: date-time description: Start time. end_time: type: string format: date-time description: End time. bucket_count: type: integer minimum: 1 maximum: 96 description: Number of activity buckets to return. required: - resource LogActivityResponse: type: object description: Bucketed runtime log activity. properties: data: type: array items: $ref: '#/components/schemas/LogActivityBucket' total: type: integer description: Total events counted across all buckets. required: - data - total LogSearchRequest: type: object description: Search request for project logs. additionalProperties: false properties: resource: $ref: '#/components/schemas/LogRequestResource' q: type: string maxLength: 512 description: Optional log query. Supports quoted text, implicit AND, AND/OR/NOT, parentheses, and fields such as `level`, `region`, `invocation.id`, `resource.id`, `resource.name`, `function`, `frontend`, `database`, and `body`. start_time: type: string format: date-time description: Start time. end_time: type: string format: date-time description: End time. limit: type: integer minimum: 1 maximum: 1000 default: 100 description: Maximum number of records to return. cursor: type: string description: Opaque pagination cursor from the previous response's `next_cursor`. required: - resource LogStreamRequest: type: object description: Stream request for live project logs. Pagination cursors and fixed end times are not supported. additionalProperties: false properties: resource: $ref: '#/components/schemas/LogRequestResource' q: type: string maxLength: 512 description: Optional log query using the same syntax as search and activity requests. start_time: type: string format: date-time description: Start time. limit: type: integer minimum: 1 maximum: 1000 default: 100 description: Maximum number of records to deliver on connect or reconnect before following new events. required: - resource LogSearchEvent: allOf: - $ref: '#/components/schemas/LogEvent' - type: object description: Runtime log event returned by project log search. Search results always include a stable event ID and owning resource. properties: id: type: string description: Opaque stable log event ID for pagination, deduplication, and display. resource: $ref: '#/components/schemas/LogResource' required: - id - resource LogSearchResponse: type: object description: Paginated project runtime log search response. properties: data: type: array items: $ref: '#/components/schemas/LogSearchEvent' description: Array of log events sorted by timestamp, newest first. limit: type: integer description: Number of items requested per page. has_more: type: boolean description: Whether there are more log events available. next_cursor: type: string description: Opaque cursor for the next page. Send this value as `cursor` on the next request. required: - data - limit - has_more FunctionRegion: type: object required: - code - label - flag properties: code: type: string example: us-east-1 description: Region identifier accepted by function APIs. label: type: string example: NA-East description: Human-readable region label suitable for display in pickers. flag: type: string example: 🇺🇸 description: Country flag emoji associated with the region's geography. FunctionRuntimeOption: type: object required: - name - language - default - durable_capable - deployment properties: name: type: string example: nodejs24.x description: Runtime identifier accepted by function APIs. language: type: string example: nodejs description: Runtime language family used by the CLI to choose defaults from source files. default: type: boolean description: Whether this runtime is the CLI default for its language. durable_capable: type: boolean description: Whether a durable function can be authored on this runtime. Only runtimes with a durable authoring API report true, and a durable deploy naming any other runtime is rejected. deployment: $ref: '#/components/schemas/FunctionRuntimeDeployment' FunctionRuntimesResponse: type: object required: - runtimes properties: runtimes: type: array items: $ref: '#/components/schemas/FunctionRuntimeOption' FunctionScheduler: type: object properties: id: type: string format: uuid project_id: type: string format: uuid function_id: type: string format: uuid function_kind: allOf: - $ref: '#/components/schemas/FunctionKind' description: | Which collection the scheduled function belongs to. A project-wide scheduler list mixes both kinds, and this is what says whether the function is read back from `/projects/{id}/functions` or `/projects/{id}/durable-functions` — and whether a tick invokes it or starts a durable execution. name: type: string enabled: type: boolean schedule_kind: type: string enum: - cron cron_expression: type: string payload: type: object additionalProperties: true regions: type: array items: type: string regions_explicit: type: boolean next_run_at: type: string format: date-time last_started_at: type: string format: date-time last_completed_at: type: string format: date-time last_error: type: string run_count: type: integer format: int64 description: Total number of times this scheduler has executed. 0 for a scheduler that has never run. created_at: type: string format: date-time updated_at: type: string format: date-time FunctionSchedulerListResponse: type: object properties: data: type: array items: $ref: '#/components/schemas/FunctionScheduler' page: type: integer limit: type: integer total: type: integer has_more: type: boolean next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only; present if has_more is true) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`. required: - data - page - limit - total - has_more HostedAuthPageType: type: string enum: - login - signup - forgot-password - device - verify-email - reset-password HostedLoginEmailCheckRequest: type: object required: - email properties: email: type: string format: email HostedLoginEmailCheckResponse: type: object properties: exists: type: boolean HostedLoginOptionsResponse: type: object properties: require_email_confirmation: type: boolean email_password_enabled: type: boolean enable_signup: type: boolean post_auth_redirect_url: type: string oauth_providers: type: array items: type: string HostedRenderablePageType: type: string enum: - signup - forgot-password - device - verify-email - reset-password LogEvent: type: object description: Historical log event returned by log APIs. properties: id: type: string description: Opaque stable log event ID for pagination, deduplication, and display. timestamp: type: string format: date-time description: Event timestamp. level: $ref: '#/components/schemas/LiveLogLevel' body: description: Application log value. JSON arguments retain their JSON type. Strings containing a serialized JSON object or array are normalized to that object or array; all other strings remain strings. nullable: true oneOf: - type: string - type: object additionalProperties: true - type: array items: {} - type: number format: double - type: boolean region: type: string description: Region where this log event originated. resource: $ref: '#/components/schemas/LogResource' deployment: $ref: '#/components/schemas/LogDeployment' invocation_id: type: string description: Function invocation ID associated with this log event, when available. required: - timestamp - body LiveLogLevel: type: string enum: - trace - debug - info - warn - error - fatal description: Canonical lowercase function runtime log level. MetricUsageData: type: object description: Usage data for one metric across totals, daily, and hourly windows. properties: metric: type: string description: | Metric name (for example, "Function & Frontend Invocations", "Frontend Requests", "Durable Executions", "Durable Operations", "Durable Compute (MB-Seconds)", "CodeBuild Build Seconds", "Bandwidth Ingress (Bytes)", "Bandwidth Egress (Bytes)", "Bandwidth Total (Bytes)", or "Database Storage (Bytes)"). Byte-based metrics are reported in bytes. "Bandwidth Total (Bytes)" is derived (ingress + egress) and is not billed separately. The three durable metrics are counted separately from "Function & Frontend Invocations", which covers standard invocations only. Operations and compute are counted when an execution finishes, so they appear in the window the execution completed in rather than the one it started in. "Durable Compute (MB-Seconds)" reports the memory the execution ran at times the time it spent running, in megabyte-seconds; the allowance for it is published in gigabyte-seconds, which is 1024 of these. "Database Storage (Bytes)" is a current observed gauge, not a cumulative counter. It is the sum of the latest samples exposed as `storage_bytes` by the project's database list, so it includes what each database's branches and backups hold, and it inherits that field's lag behind a live measurement. total: type: integer format: int64 description: Total usage for the current usage month all_time: type: integer format: int64 description: Lifetime cumulative usage across every month for this metric daily: type: array description: Last 30 days of daily usage points items: $ref: '#/components/schemas/UsageDataPoint' hourly: type: array description: Last 24 hours of hourly usage points items: $ref: '#/components/schemas/UsageDataPoint' required: - metric - total - all_time - daily - hourly OAuthConfig: type: object properties: id: type: string format: uuid provider: type: string enum: - google - github - microsoft - apple - device client_id: type: string example: 123456789.apps.googleusercontent.com client_secret: type: string description: Masked in responses (shows only first/last 4 chars) example: GOCS...**** enabled: type: boolean redirect_url: type: string format: uri example: https://yourapp.com/auth/callback scopes: type: array items: type: string example: - openid - email - profile created_at: type: string format: date-time updated_at: type: string format: date-time OAuthErrorResponse: type: object properties: error: type: string error_description: type: string required: - error PaginatedAuthUsers: type: object properties: data: type: array items: $ref: '#/components/schemas/AuthUser' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (only present if has_more is true) required: - data - page - limit - total - has_more PaginatedDatabases: type: object properties: data: type: array items: $ref: '#/components/schemas/Database' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (only present if has_more is true) next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only; present if has_more is true) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`. required: - data - page - limit - total - has_more PaginatedFrontendDeployments: type: object properties: data: type: array items: $ref: '#/components/schemas/FrontendDeployment' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (only present if has_more is true) required: - data - page - limit - total - has_more PaginatedFrontends: type: object properties: data: type: array items: $ref: '#/components/schemas/Frontend' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (offset pagination only; present if has_more is true) next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only; present if has_more is true) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`. required: - data - page - limit - total - has_more PaginatedFunctionDeployments: type: object properties: data: type: array items: $ref: '#/components/schemas/FunctionDeployment' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (only present if has_more is true) required: - data - page - limit - total - has_more PaginatedFunctions: type: object properties: data: type: array items: $ref: '#/components/schemas/Function' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (only present if has_more is true) next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only; present if has_more is true) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`. required: - data - page - limit - total - has_more PaginatedDurableFunctions: type: object properties: data: type: array items: $ref: '#/components/schemas/DurableFunction' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available required: - data - page - limit - total - has_more PaginatedDurableExecutions: type: object properties: data: type: array items: $ref: '#/components/schemas/DurableExecution' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available required: - data - page - limit - total - has_more PaginatedProjectCustomDomains: type: object properties: data: type: array items: $ref: '#/components/schemas/ProjectFrontendCustomDomain' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (only present if has_more is true) required: - data - page - limit - total - has_more PaginatedProjectDeployments: type: object properties: data: type: array items: $ref: '#/components/schemas/ProjectDeployment' page: type: integer minimum: 1 description: | Current page number (1-indexed). Offset pagination only — omitted in cursor mode, where position comes from the cursor and there is no page number to report. Required-and-1-indexed would otherwise force a `0` onto every cursor response. limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (offset pagination only; present if has_more is true) next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only; present if has_more is true) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`. required: - data - limit - total - has_more PaginatedProjects: type: object properties: data: type: array items: $ref: '#/components/schemas/Project' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (offset pagination only; present if has_more is true) next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only; present if has_more is true) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`. status: type: string enum: - provisioning - active - failed description: Latest project variable propagation status. current_sync_id: type: string format: uuid description: Identifier of the latest variable propagation sync. provisioning_started_at: type: string format: date-time description: Timestamp when the current variable propagation phase started. required: - data - page - limit - total - has_more PaginatedServiceKeys: type: object properties: data: type: array items: $ref: '#/components/schemas/ServiceKey' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (offset pagination only; present if has_more is true) next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only; present if has_more is true) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`. required: - data - page - limit - total - has_more PaginatedStorageBuckets: type: object description: Cursor-paginated storage buckets (returned only when cursor pagination is requested). properties: data: type: array items: $ref: '#/components/schemas/StorageBucket' limit: type: integer description: Number of items per page total: type: integer description: Total number of items matching the query has_more: type: boolean description: Whether a next page exists next_cursor: type: string description: Opaque cursor for the next page (present if has_more is true) prev_cursor: type: string description: Opaque cursor for the previous page (present when a previous page exists). Send as `ending_before`. required: - data - limit - has_more PaginatedVariables: type: object properties: data: type: array items: $ref: '#/components/schemas/Variable' page: type: integer description: Current page number (1-indexed) limit: type: integer description: Number of items per page total: type: integer description: Total number of items across all pages has_more: type: boolean description: Whether there are more pages available next: type: string description: URL path to next page (only present if has_more is true) next_cursor: type: string description: Opaque cursor for the next page (cursor pagination only; present if has_more is true) prev_cursor: type: string description: Opaque cursor for the previous page (cursor pagination only; present when a previous page exists). Send as `ending_before`. required: - data - page - limit - total - has_more PlatformExchangeResponse: type: object properties: token: type: string user_id: type: string token_id: type: string format: uuid expires_at: type: string format: date-time required: - token - user_id - token_id - expires_at Project: type: object properties: id: type: string format: uuid name: type: string status: type: string enum: - active - deleting - failed plan: type: string enum: - HOBBY - SUPERAGENT - FREE - PRO description: Public plan name; FREE and PRO are accepted from older Hosting responses. all_regions: type: boolean description: | Region policy for function deployment. - `true`: deploy functions to all configured platform regions - `false`: deploy only to `selected_regions` selected_regions: type: array items: type: string description: Effective region set for this project (normalized and deduplicated) aws_application_name: type: string last_invoked_at: type: string format: date-time description: Most recent activity timestamp across project resources logo_url: type: string description: | Relative API path that serves the project logo when one has been uploaded. The path is versioned with a `?v=` cache-busting query param that changes on each upload. Absent when the project has no logo. The logo image is stored in the project's storage folder. example: /projects/3fa85f64-5717-4562-b3fc-2c963f66afa6/logo?v=1718524800 git_connection: allOf: - $ref: '#/components/schemas/ProjectGitConnectionSummary' description: Present for connected projects when `git_connection` is requested through the list endpoint's `include` parameter. health: allOf: - $ref: '#/components/schemas/ProjectHealthSummary' description: Present when `health` is requested through the list endpoint's `include` parameter. created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - name - status - all_regions - selected_regions - created_at - updated_at ProjectConfig: type: object additionalProperties: false description: | Declarative project configuration manifest (the JSON form of volcano-config.yaml). Omitted sections are left untouched. Within declared entries, omitted optional fields keep their current server values (patch semantics). Declared collection keys are fully synced to the manifest: `variables`, `buckets[].policies`, `auth.providers.oauth`, `auth.email.templates`, and `functions[].schedulers` are reconciled to exactly match, deleting resources absent from the manifest. Functions, frontends, databases, and buckets are never created or deleted through this manifest; entries referencing resources that do not exist are skipped and reported. properties: version: type: integer enum: - 1 description: Manifest schema version. Must be 1. project: $ref: '#/components/schemas/ProjectConfigProject' databases: type: array items: $ref: '#/components/schemas/ProjectConfigDatabase' shared_variables: type: array uniqueItems: true description: Replace the complete shared function-variable list with existing names, without changing variable values. Omission keeps membership unchanged; an empty list clears it. items: type: string pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ variables: type: array description: Fully synced when declared - variables absent from this list are deleted. items: $ref: '#/components/schemas/ProjectConfigVariable' buckets: type: array items: $ref: '#/components/schemas/ProjectConfigBucket' realtime: $ref: '#/components/schemas/ProjectConfigRealtime' auth: $ref: '#/components/schemas/ProjectConfigAuth' functions: type: array items: $ref: '#/components/schemas/ProjectConfigFunction' frontends: type: array items: $ref: '#/components/schemas/ProjectConfigFrontend' required: - version ProjectConfigApplyResult: type: object description: Per-resource report for a project config apply (or dry run). properties: dry_run: type: boolean description: True when the request was a dry run and no changes were made. results: type: array items: $ref: '#/components/schemas/ProjectConfigApplyResultEntry' skipped: type: array description: | Manifest entries referencing functions, frontends, databases, or buckets that do not exist. Their configuration was not applied; deploy/create the resource first, then re-apply. items: $ref: '#/components/schemas/ProjectConfigSkippedResource' missing: type: array description: | Existing functions, frontends, databases, or buckets that have no entry in the corresponding declared manifest section. items: $ref: '#/components/schemas/ProjectConfigMissingResource' summary: $ref: '#/components/schemas/ProjectConfigApplySummary' required: - results - skipped - missing - summary ProjectConfigApplyResultEntry: type: object properties: section: type: string description: Manifest section the entry belongs to (e.g. variables, buckets, auth.providers.oauth). name: type: string description: Resource name or key within the section. Empty for singleton sections. action: type: string enum: - created - updated - deleted - unchanged - error error: type: string description: Error detail when action is `error`. notice: type: string description: Optional operational note (e.g. disabling realtime drops active connections). required: - section - action ProjectConfigApplySummary: type: object properties: created: type: integer updated: type: integer deleted: type: integer unchanged: type: integer errors: type: integer skipped: type: integer missing: type: integer required: - created - updated - deleted - unchanged - errors - skipped - missing ProjectConfigAuth: type: object additionalProperties: false description: Authentication settings, grouped like the dashboard auth-settings tabs. properties: tokens: $ref: '#/components/schemas/ProjectConfigAuthTokens' sessions: $ref: '#/components/schemas/ProjectConfigAuthSessions' signup: $ref: '#/components/schemas/ProjectConfigAuthSignup' rate_limits: $ref: '#/components/schemas/ProjectConfigAuthRateLimits' password: $ref: '#/components/schemas/ProjectConfigAuthPassword' password_reset: $ref: '#/components/schemas/ProjectConfigAuthPasswordReset' email_verification: $ref: '#/components/schemas/ProjectConfigAuthEmailVerification' cors: $ref: '#/components/schemas/ProjectConfigAuthCORS' providers: $ref: '#/components/schemas/ProjectConfigAuthProviders' email: $ref: '#/components/schemas/ProjectConfigAuthEmail' managed_pages: $ref: '#/components/schemas/ProjectConfigAuthManagedPages' ProjectConfigAuthCORS: type: object additionalProperties: false properties: enabled: type: boolean allowed_origins: type: array items: type: string allow_credentials: type: boolean max_age: type: integer ProjectConfigAuthEmail: type: object additionalProperties: false properties: enabled: type: boolean description: Enable transactional email sending from: $ref: '#/components/schemas/ProjectConfigAuthEmailFrom' smtp: $ref: '#/components/schemas/ProjectConfigAuthEmailSMTP' templates: $ref: '#/components/schemas/ProjectConfigEmailTemplates' ProjectConfigAuthEmailFrom: type: object additionalProperties: false properties: address: type: string name: type: string ProjectConfigAuthEmailPasswordProvider: type: object additionalProperties: false properties: enabled: type: boolean ProjectConfigAuthEmailSMTP: type: object additionalProperties: false properties: host: type: string port: type: integer username: type: string password: type: string format: password writeOnly: true description: Write-only; omitted from config export. use_tls: type: boolean ProjectConfigAuthEmailVerification: type: object additionalProperties: false properties: require_confirmation: type: boolean description: Require users to confirm email before sign-in. Requires email sending to be enabled. confirmation_timeout: type: integer description: Email confirmation token expiry in seconds ProjectConfigAuthManagedPages: type: object additionalProperties: false properties: enabled: type: boolean description: Enable or disable managed auth hosted pages redirects: $ref: '#/components/schemas/ProjectConfigAuthRedirects' pages: $ref: '#/components/schemas/ProjectConfigHostedPages' appearance: $ref: '#/components/schemas/ProjectConfigAuthPageAppearance' ProjectConfigAuthPassword: type: object additionalProperties: false properties: min_length: type: integer minimum: 15 maximum: 128 require_uppercase: type: boolean require_lowercase: type: boolean require_numbers: type: boolean require_special_chars: type: boolean ProjectConfigAuthPasswordReset: type: object additionalProperties: false properties: allow: type: boolean timeout: type: integer description: Password reset token expiry in seconds max_history: type: integer description: Number of previous passwords to disallow (0=disabled) ProjectConfigAuthProviders: type: object additionalProperties: false properties: email_password: $ref: '#/components/schemas/ProjectConfigAuthEmailPasswordProvider' oauth: type: array description: Fully synced when declared - providers absent from this list are deleted. items: $ref: '#/components/schemas/ProjectConfigOAuthProvider' ProjectConfigAuthRateLimits: type: object additionalProperties: false description: Rate limits per hour. properties: signup: type: integer signin: type: integer token_refresh: type: integer password_reset: type: integer ProjectConfigAuthRedirects: type: object additionalProperties: false properties: allowed: type: array items: type: string description: Redirect allowlist. Every entry must be a valid http/https URL. post_auth: type: string description: Must be included in `allowed` when set. post_logout: type: string description: Must be included in `allowed` when set. device_verification: type: string description: Optional custom device-authorization verification page URL. ProjectConfigAuthSessions: type: object additionalProperties: false properties: inactivity_timeout: type: integer description: Force re-login after inactivity (seconds, 0=never) max_session_duration: type: integer description: Force re-login after duration (seconds, 0=never) ProjectConfigAuthSignup: type: object additionalProperties: false properties: enable_signup: type: boolean description: Master switch for signups across ALL providers enable_anonymous_signins: type: boolean allowed_email_domains: type: array maxItems: 100 description: | Email domains allowed to create users. Empty allows every domain. Replaces the stored list; entries are normalized (lowercase, no `@` prefix) and must be bare domains such as `domain1.com`. Matching is exact, so subdomains need their own entry. At most 100 entries. Restricting signups is a SUPERAGENT feature to configure and to enforce: a HOBBY project can only declare the list it already has or remove the restriction, and the list it keeps is parked until it upgrades. items: type: string example: - domain1.com - domain2.com allowed_email_domains_mode: type: string description: | How far `allowed_email_domains` reaches. `signup` gates account creation only. `signup_and_signin` also blocks sign-in for accounts outside the list and signs out the ones it locks out. `disabled` keeps the list without enforcing it. enum: - disabled - signup - signup_and_signin ProjectConfigAuthTokens: type: object additionalProperties: false description: Token lifetimes in seconds. properties: access_token_lifetime: type: integer refresh_token_lifetime: type: integer refresh_token_reuse_interval: type: integer platform_token_ttl: type: integer ProjectConfigBucket: type: object additionalProperties: false description: | Settings for an existing storage bucket. Buckets are never created or deleted through the manifest. When `policies` is declared it is fully synced (policies absent from the list are deleted; an empty list deletes all); omitting `policies` leaves the bucket's policies untouched. properties: name: type: string pattern: ^[a-zA-Z0-9_-]+$ minLength: 1 maxLength: 64 file_size_limit: type: integer format: int64 description: Maximum file size in bytes allowed_mime_types: type: array items: type: string policies: type: array items: $ref: '#/components/schemas/ProjectConfigBucketPolicy' required: - name ProjectConfigBucketPolicy: type: object additionalProperties: false properties: name: type: string minLength: 1 operation: type: string enum: - SELECT - INSERT - UPDATE - DELETE definition: type: string description: Policy expression required: - name - operation - definition ProjectConfigCustomDomain: type: object additionalProperties: false description: | Custom domain with managed or BYOC TLS (SUPERAGENT plan). `tls` is required when the domain is first created and optional afterwards. For an existing domain, omitting `tls` or sending only `tls.mode` keeps the stored certificate; new BYOC material for the same domain rotates the certificate in place (zero downtime). Changing `tls.mode` for the same hostname, or the hostname of a managed domain, requires deleting the domain first. BYOC TLS material is write-only; exports render only `tls.mode`. properties: domain: type: string maxLength: 253 description: 'Fully-qualified domain name (hostname only, no scheme/path). Managed TLS (`tls.mode: managed`) accepts at most 219 characters; BYOC accepts 253.' tls: $ref: '#/components/schemas/ProjectConfigFrontendCustomDomainTLSConfig' required: - domain ProjectConfigDatabase: type: object additionalProperties: false description: | Assertion-only entry for an existing database. No database property is mutable through the manifest; declared values are compared against the deployed database and any mismatch fails validation. Databases are never created or deleted here. properties: name: type: string minLength: 1 region: type: string description: Deployed region ID (e.g. aws-us-east-1). Asserted, never written. pg_version: type: string enum: - '15' - '16' description: PostgreSQL major version. Asserted, never written. database_type: type: string enum: - volcano-db-xs - volcano-db-s - volcano-db-m - volcano-db-l - volcano-db-xl - volcano-db-2xl description: | Compute tier. Asserted, never written - tier changes are not supported via the manifest; use the databases API/CLI/GUI instead. required: - name - region - pg_version ProjectConfigEmailTemplate: type: object additionalProperties: false properties: subject: type: string html_body: type: string maxLength: 262144 description: HTML body. Max 256 KiB. SUPERAGENT plan required for custom bodies. text_body: type: string maxLength: 262144 description: Plain-text body. Max 256 KiB. SUPERAGENT plan required for custom bodies. ProjectConfigEmailTemplates: type: object additionalProperties: false description: | Email templates keyed by type. Fully synced when declared - template types absent from a declared map revert to server defaults (custom bodies deleted, subject overrides cleared). Custom template bodies require the SUPERAGENT plan; subject-only changes are available on HOBBY. properties: confirmation: $ref: '#/components/schemas/ProjectConfigEmailTemplate' password_reset: $ref: '#/components/schemas/ProjectConfigEmailTemplate' password_changed: $ref: '#/components/schemas/ProjectConfigEmailTemplate' welcome: $ref: '#/components/schemas/ProjectConfigEmailTemplate' ProjectConfigFrontend: type: object additionalProperties: false description: | Configuration for an existing (deployed) frontend. Frontends are never created or deleted through the manifest. A declared frontend entry without `custom_domain` deletes an existing custom domain. properties: name: type: string minLength: 1 custom_domain: $ref: '#/components/schemas/ProjectConfigCustomDomain' required: - name ProjectConfigFunction: type: object additionalProperties: false description: | Configuration for an existing (deployed) function. Functions are never created or deleted through the manifest. When `schedulers` is declared it is fully synced (schedulers absent from the list are deleted); omitting `schedulers` leaves the function's schedulers untouched. The same applies to `variables`: declaring it replaces the function's declared variable names, and omitting it leaves them untouched. properties: name: type: string minLength: 1 kind: $ref: '#/components/schemas/FunctionKind' public: type: boolean description: Function visibility for anon-key invocation variable_scope: type: string enum: - all - scoped description: | Which project variables this function receives. `all` (the default) gives it the project variables marked `shared: true`. `scoped` gives it only the variables it selects: every name declared in `variables`, plus the names Volcano detects in its source that the project defines. variables: type: array items: type: string minLength: 1 maxLength: 256 description: | Project variable names this function requires, on top of the ones detected in its source. Declare a name here when the function reads it through a computed key, which detection cannot see, or when the function must not deploy without it: a declared name the project does not define fails the apply, while a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. invocation_mode: $ref: '#/components/schemas/FunctionInvocationMode' http_auth_mode: $ref: '#/components/schemas/FunctionHTTPAuthMode' openapi_spec: type: object nullable: true additionalProperties: true x-go-type: nullable.Nullable[map[string]interface{}] x-go-type-skip-optional-pointer: true description: OpenAPI 3.0 or 3.1 metadata for an HTTP-mode function schedulers: type: array items: $ref: '#/components/schemas/ProjectConfigScheduler' required: - name ProjectConfigHostedPage: type: object additionalProperties: false properties: html: type: string maxLength: 262144 description: Raw HTML markup for the page. Max 256 KiB. css: type: string maxLength: 262144 description: Optional CSS injected at render time. Max 256 KiB. required: - html ProjectConfigHostedPages: type: object additionalProperties: false description: | Hosted auth pages keyed by page type (SUPERAGENT plan). Upsert-only: omitted pages are left untouched (there is no delete for hosted pages). properties: login: $ref: '#/components/schemas/ProjectConfigHostedPage' reset_password: $ref: '#/components/schemas/ProjectConfigHostedPage' signup: $ref: '#/components/schemas/ProjectConfigHostedPage' forgot_password: $ref: '#/components/schemas/ProjectConfigHostedPage' device: $ref: '#/components/schemas/ProjectConfigHostedPage' verify_email: $ref: '#/components/schemas/ProjectConfigHostedPage' PreviewAuthPageRequest: type: object additionalProperties: false required: - theme - layout properties: theme: $ref: '#/components/schemas/AuthPageTheme' layout: $ref: '#/components/schemas/AuthPageLayout' action: type: string PreviewAuthPageResponse: type: object required: - preview_url - expires_at properties: preview_url: type: string format: uri expires_at: type: string format: date-time ProjectConfigMissingResource: type: object properties: type: type: string enum: - function - frontend - database - bucket name: type: string required: - type - name ProjectConfigOAuthProvider: type: object additionalProperties: false properties: provider: type: string enum: - google - github - microsoft - apple - device enabled: type: boolean client_id: type: string description: | Required for non-device providers. Server-generated for `provider=device` (exported read-only, ignored on apply). client_secret: type: string format: password writeOnly: true description: Write-only; omitted from config export. Not used for `provider=device`. redirect_url: type: string description: Not used for `provider=device`. scopes: type: array items: type: string required: - provider ProjectConfigProject: type: object additionalProperties: false description: Project-level settings. `name` renames the project. properties: name: type: string pattern: ^[A-Za-z0-9_-]+$ minLength: 1 maxLength: 255 all_regions: type: boolean description: Region policy. `false` requires `selected_regions` (SUPERAGENT plan). selected_regions: type: array items: type: string description: Region subset (bare region names). Requires `all_regions=false`. ProjectConfigRealtime: type: object additionalProperties: false properties: enabled: type: boolean broadcast_enabled: type: boolean presence_enabled: type: boolean postgres_changes_enabled: type: boolean ProjectConfigScheduler: type: object additionalProperties: false properties: name: type: string minLength: 1 maxLength: 200 cron: type: string description: 5-field UTC cron expression enabled: type: boolean payload: type: object additionalProperties: true required: - name - cron ProjectConfigSkippedResource: type: object properties: type: type: string enum: - function - frontend - database - bucket name: type: string reason: type: string required: - type - name - reason ProjectConfigValidationError: type: object properties: section: type: string description: Manifest section the error refers to (e.g. databases, functions). name: type: string description: Resource name or key within the section, when applicable. message: type: string required: - section - message ProjectConfigValidationErrorResponse: type: object description: Returned when manifest validation fails. Nothing was applied. properties: error: type: string errors: type: array items: $ref: '#/components/schemas/ProjectConfigValidationError' required: - error - errors ProjectConfigVariable: type: object additionalProperties: false properties: shared: type: boolean description: Include this name in the project's shared function variables. Omission preserves existing membership; new variables default to true for legacy clients. Send false explicitly to create a non-shared variable. name: type: string minLength: 1 value: type: string required: - name - value ProjectHealthResource: type: object properties: type: type: string enum: - project - function - frontend - database id: type: string format: uuid name: type: string kind: allOf: - $ref: '#/components/schemas/FunctionKind' description: | Which kind of function this check is about. Present only when `type` is `function`, where both kinds share the name space and this is what tells them apart. required: - type - id - name ResourceReference: type: object description: Stable reference to a Volcano resource. properties: type: type: string enum: - project - function - frontend - database id: type: string format: uuid name: type: string required: - type - id - name DeploymentReference: type: object description: Stable reference to a Volcano deployment run. properties: id: type: string format: uuid required: - id ProjectHealthScope: type: object properties: resource: $ref: '#/components/schemas/ProjectHealthResource' required: - resource ProjectHealthResponse: type: object properties: project_id: type: string format: uuid status: $ref: '#/components/schemas/ProjectHealthStatus' observed_at: type: string format: date-time fresh_through: type: string format: date-time data_status: $ref: '#/components/schemas/ProjectHealthDataStatus' checks: type: array items: $ref: '#/components/schemas/ProjectHealthCheck' findings: description: Top findings ordered by severity, then stable check ID. type: array maxItems: 5 items: $ref: '#/components/schemas/ProjectHealthCheck' required: - project_id - status - observed_at - fresh_through - data_status - checks - findings ProjectHealthStatus: type: string enum: - healthy - degraded - critical - unknown ProjectHealthDataStatus: type: string enum: - complete - partial - no_data - stale ProjectHealthCategory: type: string enum: - lifecycle - storage ProjectHealthEvidence: type: object properties: metric: type: string value: type: number format: double unit: type: string sample_count: type: integer format: int64 minimum: 0 required: - metric - value - unit - sample_count ProjectHealthCheck: type: object properties: id: type: string category: $ref: '#/components/schemas/ProjectHealthCategory' status: $ref: '#/components/schemas/ProjectHealthStatus' reason_code: type: string scope: $ref: '#/components/schemas/ProjectHealthScope' evidence: $ref: '#/components/schemas/ProjectHealthEvidence' required: - id - category - status - reason_code - scope - evidence ProjectMetricsDataStatus: type: string enum: - complete - partial - no_data ProjectMetricsDimensions: type: object additionalProperties: false properties: region: type: string resource_type: type: string enum: - function - frontend ProjectMetricsGroupBy: type: string enum: - region - resource_type ProjectMetricsMetric: type: string enum: - request_count - server_error_count - availability - p95_latency ProjectMetricsQuery: type: object additionalProperties: false properties: id: type: string minLength: 1 maxLength: 64 pattern: ^[A-Za-z][A-Za-z0-9_-]*$ metric: $ref: '#/components/schemas/ProjectMetricsMetric' group_by: $ref: '#/components/schemas/ProjectMetricsGroupBy' required: - id - metric ProjectMetricsQueryRequest: type: object additionalProperties: false properties: time_range: $ref: '#/components/schemas/ProjectMetricsQueryTimeRange' queries: type: array minItems: 1 maxItems: 10 items: $ref: '#/components/schemas/ProjectMetricsQuery' required: - time_range - queries ProjectMetricsQueryResponse: type: object additionalProperties: false properties: observed_at: type: string format: date-time fresh_through: type: string format: date-time window: $ref: '#/components/schemas/ProjectMetricsWindow' results: type: array items: $ref: '#/components/schemas/ProjectMetricsResult' required: - observed_at - window - results ProjectMetricsQueryTimeRange: type: object additionalProperties: false properties: window: type: string enum: - 30m - 1h - 24h - 7d required: - window ProjectMetricsResult: type: object additionalProperties: false properties: id: type: string metric: $ref: '#/components/schemas/ProjectMetricsMetric' unit: $ref: '#/components/schemas/ProjectMetricsUnit' data_status: $ref: '#/components/schemas/ProjectMetricsDataStatus' values: type: array items: $ref: '#/components/schemas/ProjectMetricsValue' required: - id - metric - unit - data_status - values ProjectMetricsUnit: type: string enum: - count - ratio - seconds ProjectMetricsValue: type: object additionalProperties: false properties: dimensions: $ref: '#/components/schemas/ProjectMetricsDimensions' value: type: number format: double minimum: 0 required: - dimensions - value ProjectMetricsWindow: type: object properties: from: type: string format: date-time to: type: string format: date-time required: - from - to ProjectFrontendCustomDomain: allOf: - $ref: '#/components/schemas/FrontendCustomDomainResponse' - type: object properties: frontend: type: object description: | The frontend this custom domain is attached to. Inlined to avoid a second fetch from the project-scoped feed. properties: id: type: string format: uuid name: type: string required: - id - name required: - frontend ProjectDeployment: type: object description: A Function or Frontend deployment attempt in a project-scoped feed. properties: id: type: string format: uuid project_id: type: string format: uuid resource: $ref: '#/components/schemas/ProjectDeploymentResource' operation: type: string enum: - deploy - redeploy - update - delete status: type: string enum: - queued - provisioning - active - degraded - failed - superseded - deleting - deleted deploy_source: type: string enum: - git - cli - web - api - system - unknown description: What initiated this deployment. artifact_version: type: string error_message: type: string completed_at: type: string format: date-time progress: $ref: '#/components/schemas/DeploymentProgress' created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - project_id - resource - operation - status - deploy_source - created_at - updated_at ProjectDeploymentResource: type: object description: The resource this deployment belongs to. properties: type: type: string enum: - function - frontend id: type: string format: uuid name: type: string kind: allOf: - $ref: '#/components/schemas/FunctionKind' description: | Which kind of function this deployment belongs to. Both kinds appear in this feed under `type: function`, because a deployment means the same thing for either, so this is what tells them apart. Absent when `type` is `frontend`. required: - type - id - name ProjectDeploymentSummary: type: object description: Aggregate deployment statistics for one resource pipeline. properties: deployment_count: type: integer description: All deployment attempts matching the filters. successful_count: type: integer description: Attempts that reached active or deleted. failed_count: type: integer description: Attempts that reached failed or degraded. canceled_count: type: integer description: Superseded attempts, excluded from success rate and duration. success_rate: type: number format: double minimum: 0 maximum: 1 nullable: true description: Successful attempts divided by successful plus failed attempts. median_build_duration_seconds: type: number format: double minimum: 0 nullable: true description: Median CodeBuild duration across eligible completed attempts. required: - deployment_count - successful_count - failed_count - canceled_count - success_rate - median_build_duration_seconds ProjectUsageResponse: type: object description: Aggregated usage metrics for a project. properties: project_id: type: string format: uuid description: Project ID month: type: string description: Usage month in YYYY-MM format example: 2026-02 metrics: type: array description: Usage metrics for the project items: $ref: '#/components/schemas/MetricUsageData' frontends: type: array description: Per-frontend request totals for the current usage month items: $ref: '#/components/schemas/FrontendUsageData' required: - project_id - month - metrics RealtimeConfig: type: object description: | Realtime configuration for a project. Note: Message size and channels per connection are plan-based (not configurable). properties: project_id: type: string format: uuid description: Project ID enabled: type: boolean description: Whether realtime is enabled for this project default: false broadcast_enabled: type: boolean description: Whether broadcast channels are enabled default: true presence_enabled: type: boolean description: Whether presence tracking is enabled default: true postgres_changes_enabled: type: boolean description: Whether Postgres change notifications are enabled default: true created_at: type: string format: date-time description: When the configuration was created updated_at: type: string format: date-time description: When the configuration was last updated RealtimePlanLimits: type: object description: Plan-based limits for realtime features properties: plan: type: string description: Public plan name (HOBBY or SUPERAGENT). example: HOBBY max_connections: type: integer description: Maximum concurrent connections allowed example: 100 messages_per_month: type: integer description: Maximum messages per month example: 1000000 message_size_kb: type: integer description: Maximum message size in KB example: 32 channels_per_conn: type: integer description: Maximum channels per connection example: 100 RealtimeStats: type: object description: Realtime usage statistics for a project properties: num_connections: type: integer description: Current number of active connections peak_connections: type: integer description: Peak concurrent connections this usage period last_invoked_at: type: string format: date-time description: Most recent realtime activity timestamp across channels limits: $ref: '#/components/schemas/RealtimePlanLimits' ResolveFunctionResponse: type: object properties: name: type: string maxLength: 63 pattern: ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ description: DNS-safe function name function_id: type: string format: uuid description: Canonical function ID used for invocation routing invoke_url: type: string description: 'Canonical HTTPS endpoint for invoking this function. Use it as-is: it does not share a domain with the API, so a host derived from the API URL will not reach the function. Omitted when the deployment serves no public invocation domain, as in local development; invoke through POST /functions/{functionId}/invoke instead.' cache_ttl_seconds: type: integer minimum: 1 description: Suggested SDK cache TTL for this name-to-ID mapping required: - name - function_id - cache_ttl_seconds ScheduleRequest: type: object required: - cron_expression properties: kind: type: string enum: - cron default: cron cron_expression: type: string description: Standard 5-field cron expression evaluated in UTC. Seconds fields, descriptors, and Quartz syntax are not supported. example: '*/5 * * * *' ServiceKey: type: object description: | Service role key for admin operations. **WARNING:** Bypasses all RLS - backend use only! properties: id: type: string format: uuid project_id: type: string format: uuid name: type: string description: Descriptive name for the key key_value: type: string description: | Full JWT token for Authorization header. Returned on create, get, and list (decrypted from storage). **Store securely - NEVER expose in frontend code!** key_prefix: type: string description: First 12 characters of the key for display/identification maxLength: 12 permissions: type: array items: type: string description: | Operations this key may perform. ["*"] grants full admin access (default for keys created without an explicit scope). Scoped keys list specific permissions, e.g. ["functions.invoke", "locks.manage"]. example: - '*' created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - name - key_prefix - permissions StorageBucket: type: object description: | A named container for files within a project. Public access is controlled at the file level via is_public on StorageObject. properties: id: type: string format: uuid project_id: type: string format: uuid name: type: string description: Bucket name (unique within project) pattern: ^[a-zA-Z0-9_-]+$ minLength: 1 maxLength: 64 file_size_limit: type: integer format: int64 nullable: true description: Maximum file size in bytes (null for no limit) allowed_mime_types: type: array nullable: true items: type: string description: Allowed MIME types (null for all types) last_invoked_at: type: string format: date-time description: Most recent bucket operation timestamp created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - name StorageCopyRequest: type: object properties: from: type: string description: Source path to: type: string description: Destination path required: - from - to StorageListResponse: type: object properties: objects: type: array items: $ref: '#/components/schemas/StorageObject' next_cursor: type: string description: Cursor for next page (empty if no more results) StorageMoveRequest: type: object properties: from: type: string description: Source path to: type: string description: Destination path required: - from - to StorageObject: type: object properties: id: type: string format: uuid bucket_id: type: string format: uuid name: type: string description: Full path within bucket (e.g., "users/abc123/avatar.png") owner_id: type: string format: uuid nullable: true description: Auth user who uploaded (null for anonymous/service) is_public: type: boolean default: false description: | If true, the file can be downloaded with just an anon key (no user authentication). Files are private by default. Only the owner or a service key can change visibility. size: type: integer format: int64 description: File size in bytes mime_type: type: string description: MIME type etag: type: string description: Entity tag for cache validation metadata: type: object additionalProperties: true description: | Custom user metadata (key-value pairs). Limits: Maximum 50 keys, maximum 10KB total serialized size. created_at: type: string format: date-time updated_at: type: string format: date-time public_url: type: string format: uri description: | Shareable public URL for this file (only set for public files with is_public=true). This URL requires NO authentication and can be embedded in HTML, shared via email, etc. The URL is properly URL-encoded by the server - use it as-is without additional encoding. required: - id - bucket_id - name - is_public - size - mime_type StorageObjectWithBucket: type: object description: Storage object with bucket name included (for admin listing across buckets) properties: id: type: string format: uuid bucket_id: type: string format: uuid bucket_name: type: string description: Name of the bucket containing this object name: type: string description: Full path within bucket owner_id: type: string format: uuid nullable: true description: Auth user who uploaded (null for anonymous/service) is_public: type: boolean default: false size: type: integer format: int64 description: File size in bytes mime_type: type: string etag: type: string metadata: type: object additionalProperties: true created_at: type: string format: date-time updated_at: type: string format: date-time public_url: type: string format: uri description: | Shareable public URL for this file (only set for public files with is_public=true). This URL requires NO authentication and can be embedded in HTML, shared via email, etc. required: - id - bucket_id - bucket_name - name - is_public - size - mime_type StoragePolicy: type: object properties: id: type: string format: uuid bucket_id: type: string format: uuid name: type: string description: Policy name (unique within bucket) operation: type: string enum: - SELECT - INSERT - UPDATE - DELETE description: Operation this policy applies to definition: type: string description: | Policy expression evaluated at request time. Examples: - "true" - Allow all - "auth.uid() = owner_id" - Owner only - "auth.role() = 'authenticated'" - Authenticated users - "(storage.foldername(name))[1] = auth.uid()::text" - User's folder created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - bucket_id - name - operation - definition StorageStats: type: object description: Aggregate storage statistics for a project properties: bucket_count: type: integer description: Number of storage buckets object_count: type: integer description: Total number of stored files total_size: type: integer format: int64 description: Total storage used in bytes required: - bucket_count - object_count - total_size StorageVisibilityRequest: type: object properties: is_public: type: boolean description: Whether the file should be publicly accessible required: - is_public UnbanUserResponse: type: object description: Response when unbanning a user properties: message: type: string example: User unbanned successfully user_id: type: string format: uuid email: type: string format: email status: type: string enum: - active required: - message - user_id - email - status TestEmailRequest: type: object required: - to_email description: | When `html_body` or `text_body` is provided the backend renders those (plus optional `subject`) through html/text templates against the standard `Data` (ProjectName, Name, SiteURL) and sends the result — used by the template-editor "Send Test" affordance to preview an unsaved template. When both bodies are omitted a hardcoded diagnostic message is sent to verify SMTP credentials and `subject` is ignored. Sending `subject` alone (without a body) is rejected with 400. properties: to_email: type: string format: email description: Recipient address for the diagnostic email. subject: type: string description: | Optional subject override, rendered as a text/template. Only applied on the override path — requires `html_body` or `text_body` to also be set, otherwise the request is rejected with 400. html_body: type: string maxLength: 262144 description: Optional HTML body override. Rendered as an html/template. Max 256 KiB. text_body: type: string maxLength: 262144 description: Optional plain-text body override. Rendered as a text/template. Max 256 KiB. TestEmailResponse: type: object required: - success properties: success: type: boolean UpdateAuthConfigRequest: type: object description: 'All fields optional - only include fields you want to update. Validation rule: require_email_confirmation=true requires email_enabled=true.' properties: access_token_lifetime: type: integer refresh_token_lifetime: type: integer inactivity_timeout: type: integer max_session_duration: type: integer min_password_length: type: integer minimum: 15 maximum: 128 require_uppercase: type: boolean require_lowercase: type: boolean require_numbers: type: boolean require_special_chars: type: boolean enable_signup: type: boolean description: Master switch for signups across ALL providers enable_email_password: type: boolean description: Enable/disable email/password provider rate_limit_signup: type: integer rate_limit_signin: type: integer rate_limit_token_refresh: type: integer cors_allow_credentials: type: boolean cors_max_age: type: integer enable_anonymous_signins: type: boolean allowed_email_domains: type: array maxItems: 100 description: | Replaces the email domain allowlist. Empty array removes the restriction so any domain can sign up. Entries must be bare domains such as `domain1.com` and are stored normalized (lowercase, no `@` prefix); matching is exact, so subdomains need their own entry. At most 100 entries. Restricting signups is a SUPERAGENT feature to configure and to enforce: a HOBBY project can only remove the restriction and gets 403 for any other change, and the list it keeps is parked until it upgrades. items: type: string example: - domain1.com - domain2.com allowed_email_domains_mode: type: string description: | How far `allowed_email_domains` reaches. `signup` gates account creation only. `signup_and_signin` also blocks sign-in for accounts outside the list; switching to it, or narrowing the list while in it, deletes the sessions of every account it locks out. `disabled` keeps the list without enforcing it. enum: - disabled - signup - signup_and_signin allow_password_reset: type: boolean password_reset_timeout: type: integer max_password_history: type: integer require_email_confirmation: type: boolean description: Require users to confirm email before sign-in. Can only be true when email_enabled is true. email_confirmation_timeout: type: integer description: Email confirmation token expiry in seconds. auto_link_verified_oauth: type: boolean description: Link a verified OAuth identity to an existing confirmed account with the same email instead of returning a conflict. Requires require_email_confirmation to be true. email_enabled: type: boolean description: Enable transactional email sending. Cannot be false while require_email_confirmation is true. email_from_address: type: string email_from_name: type: string smtp_host: type: string smtp_port: type: integer smtp_username: type: string smtp_password: type: string format: password writeOnly: true minLength: 1 description: Replacement SMTP password. Omit this field to preserve the configured password. The value is encrypted at rest and never returned. smtp_use_tls: type: boolean email_confirmation_subject: type: string email_password_reset_subject: type: string email_password_changed_subject: type: string managed_auth_enabled: type: boolean description: Enable or disable managed auth hosted pages for the project. post_auth_redirect_url: type: string description: Must be included in allowed_redirect_urls when set. allowed_redirect_urls: type: array items: type: string description: Redirect allowlist. Every entry must be a valid http/https URL. post_logout_redirect_url: type: string description: Must be included in allowed_redirect_urls when set. device_verification_url: type: string description: | Optional custom device-authorization verification page. Must be a valid http/https URL (not tied to allowed_redirect_urls). When set, device-code logins return this URL (with user_code) instead of the managed device page. Send an empty string to clear the override. UpdateAuthHostedPageRequest: type: object required: - html properties: html: type: string description: Raw HTML markup for the page. Max 256 KiB. css: type: string description: Optional CSS injected at render time. Max 256 KiB. UpdateAuthPageLayoutRequest: type: object additionalProperties: false required: - layout properties: layout: $ref: '#/components/schemas/AuthPageLayout' UpdateAuthPageThemeRequest: type: object additionalProperties: false required: - theme properties: theme: $ref: '#/components/schemas/AuthPageTheme' UpdateDatabaseTypeRequest: type: object description: Update database compute size tier properties: database_type: type: string description: New compute size tier enum: - volcano-db-xs - volcano-db-s - volcano-db-m - volcano-db-l - volcano-db-xl - volcano-db-2xl example: volcano-db-m required: - database_type UpdateEmailTemplateRequest: type: object properties: subject: type: string html_body: type: string text_body: type: string UpdateFunctionRequest: type: object additionalProperties: false minProperties: 1 properties: is_public: type: boolean description: | Function visibility for anon-key invocation. - `false` (default): private function - `true`: public function (anon keys with `functions.invoke` can invoke) invocation_mode: $ref: '#/components/schemas/FunctionInvocationMode' http_auth_mode: $ref: '#/components/schemas/FunctionHTTPAuthMode' openapi_spec: type: object nullable: true additionalProperties: true description: OpenAPI 3.0 or 3.1 metadata for HTTP mode. Send null to clear it. UpdateFunctionSchedulerRequest: type: object properties: name: type: string maxLength: 200 enabled: type: boolean schedule: $ref: '#/components/schemas/ScheduleRequest' payload: type: object additionalProperties: true regions: type: array maxItems: 1 items: type: string UpdateOAuthConfigRequest: type: object properties: client_id: type: string description: Supported for non-device providers. Not supported for `provider=device`. client_secret: type: string description: Supported for non-device providers. Not supported for `provider=device`. redirect_url: type: string format: uri scopes: type: array items: type: string enabled: type: boolean UpdateProjectRequest: type: object description: Update mutable project fields (name and/or region policy) properties: name: type: string minLength: 1 maxLength: 255 example: my-awesome-app-renamed all_regions: type: boolean description: | If omitted and `selected_regions` is also omitted, existing region policy is preserved. If `selected_regions` is provided without `all_regions`, it is treated as subset mode. selected_regions: type: array items: type: string description: | Region subset for project deployments. Provide with `all_regions=false`. example: - us-east-1 UpdateRealtimeConfigRequest: type: object description: | Request to update realtime configuration. Limits (message size, channels per connection) are plan-based and cannot be configured. properties: enabled: type: boolean description: Whether realtime is enabled for this project broadcast_enabled: type: boolean description: Whether broadcast channels are enabled presence_enabled: type: boolean description: Whether presence tracking is enabled postgres_changes_enabled: type: boolean description: Whether Postgres change notifications are enabled UpdateStorageBucketRequest: type: object properties: file_size_limit: type: integer format: int64 allowed_mime_types: type: array items: type: string UpdateVariableRequest: type: object properties: shared: type: boolean description: Include this name in the project's shared function variables. Omission preserves existing membership; new variables default to true for legacy clients. Send false explicitly to create a non-shared variable. value: type: string required: - value UploadSessionPart: type: object description: Information about an uploaded part properties: part_number: type: integer description: Part number (1-10000) etag: type: string description: ETag of the uploaded part size: type: integer format: int64 description: Size of the part in bytes UploadSessionStatusResponse: type: object description: Status of an upload session properties: session_id: type: string description: Upload session ID status: type: string enum: - pending - uploading - completing - completed - aborted description: Current status of the upload path: type: string description: Target file path content_type: type: string description: MIME type total_size: type: integer format: int64 description: Total file size in bytes part_size: type: integer format: int64 description: Size of each part (except last) total_parts: type: integer description: Total number of parts parts_uploaded: type: integer description: Number of parts uploaded bytes_uploaded: type: integer format: int64 description: Total bytes uploaded so far parts: type: array description: List of uploaded parts (for resume) items: $ref: '#/components/schemas/UploadSessionPart' expires_at: type: string format: date-time description: Session expiry time created_at: type: string format: date-time description: Session creation time UsageDataPoint: type: object description: A single timestamped usage value. properties: timestamp: type: string format: date-time description: UTC timestamp for the data point value: type: integer format: int64 description: Usage value at the timestamp required: - timestamp - value Variable: type: object properties: shared: type: boolean description: Include this name in the project's shared function variables. Omission preserves existing membership; new variables default to true for legacy clients. Send false explicitly to create a non-shared variable. id: type: string format: uuid project_id: type: string format: uuid name: type: string maxLength: 256 value: type: string status: type: string enum: - provisioning - active - failed description: Latest project variable propagation status, when a sync has run. current_sync_id: type: string format: uuid description: Identifier of the latest variable propagation sync. provisioning_started_at: type: string format: date-time description: Timestamp when the current variable propagation phase started. deploy_source: type: string enum: - git - cli - web - api - system - unknown description: What initiated the latest variable propagation sync, when one has run. created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - project_id - name - value - created_at - updated_at ProjectGitConnectionSummary: type: object properties: repo_installation_id: type: integer format: int64 repo_id: type: integer format: int64 repo_full_name: type: string root_directory: type: string production_branch: type: string updated_at: type: string format: date-time required: - repo_installation_id - repo_id - repo_full_name - root_directory - production_branch - updated_at ProjectHealthSummary: type: object properties: status: $ref: '#/components/schemas/ProjectHealthStatus' required: - status FunctionKind: type: string enum: - standard - durable default: standard description: | Which kind of function this is. `standard` runs once per invocation. `durable` checkpoints its progress and resumes from the last completed step, and is invoked asynchronously through its own executions collection. A function's kind is fixed when it is created and cannot be changed afterwards. Omitting this field means `standard`. AuthPageThemeColors: type: object additionalProperties: false required: - background - surface - text - accent - accent_text properties: background: type: string pattern: ^#[0-9a-fA-F]{6}$ surface: type: string pattern: ^#[0-9a-fA-F]{6}$ text: type: string pattern: ^#[0-9a-fA-F]{6}$ accent: type: string pattern: ^#[0-9a-fA-F]{6}$ accent_text: type: string pattern: ^#[0-9a-fA-F]{6}$ ProjectConfigAuthPageLayouts: type: object additionalProperties: false properties: login: $ref: '#/components/schemas/AuthPageLayout' signup: $ref: '#/components/schemas/AuthPageLayout' forgot_password: $ref: '#/components/schemas/AuthPageLayout' device: $ref: '#/components/schemas/AuthPageLayout' verify_email: $ref: '#/components/schemas/AuthPageLayout' reset_password: $ref: '#/components/schemas/AuthPageLayout' ProjectConfigAuthPageAppearance: type: object additionalProperties: false properties: theme: $ref: '#/components/schemas/AuthPageTheme' layouts: $ref: '#/components/schemas/ProjectConfigAuthPageLayouts' ManagedProjectConfigFrontendCustomDomainTLSConfig: type: object description: Volcano issues and renews the certificate. Certificate fields are not allowed. additionalProperties: false properties: mode: type: string enum: - managed required: - mode BYOCProjectConfigFrontendCustomDomainTLSConfig: type: object description: 'Your own certificate. Send `certificate_pem` and `private_key_pem` together, with an optional `certificate_chain_pem`, to create the domain or rotate its certificate. For an existing BYOC domain, `mode: byoc` without certificate fields keeps the stored certificate; exports render only the mode.' additionalProperties: false not: anyOf: - required: - certificate_pem not: required: - private_key_pem - required: - private_key_pem not: required: - certificate_pem - required: - certificate_chain_pem not: required: - certificate_pem - private_key_pem properties: mode: type: string enum: - byoc description: Optional; a TLS block without `mode` is BYOC. certificate_pem: type: string maxLength: 65536 description: PEM-encoded certificate for create or rotation. Requires private_key_pem. Omitted from exports. private_key_pem: type: string maxLength: 65536 description: PEM-encoded private key for create or rotation. Requires certificate_pem. Omitted from exports. certificate_chain_pem: type: string maxLength: 65536 description: Optional PEM-encoded certificate chain. Requires certificate_pem and private_key_pem. Omitted from exports. ProjectConfigFrontendCustomDomainTLSConfig: description: TLS for the custom domain. `mode` defaults to `byoc` when omitted. oneOf: - $ref: '#/components/schemas/ManagedProjectConfigFrontendCustomDomainTLSConfig' - $ref: '#/components/schemas/BYOCProjectConfigFrontendCustomDomainTLSConfig' DatabaseQueryPerformanceDatabase: type: object properties: id: type: string format: uuid name: type: string required: - id - name DatabaseQueryPerformanceItem: type: object properties: query_id: type: string description: pg_stat_statements query identifier. query: type: string maxLength: 8192 description: Normalized and obfuscated representative query text. database: $ref: '#/components/schemas/DatabaseQueryPerformanceDatabase' role: type: string description: Database role used for the query. calls: type: integer format: int64 total_exec_time_seconds: type: number format: double description: Cumulative total execution time from pg_stat_statements in seconds. max_exec_time_seconds: type: number format: double mean_exec_time_seconds: type: number format: double min_exec_time_seconds: type: number format: double rows_processed: type: integer format: int64 required: - query_id - query - database - role - calls - total_exec_time_seconds - max_exec_time_seconds - mean_exec_time_seconds - min_exec_time_seconds - rows_processed DeploymentPhase: type: object description: Timing and outcome for one normalized deployment pipeline phase. properties: name: type: string enum: - queue - checkout - build - image - provisioning - rollout - verification status: type: string enum: - pending - in_progress - succeeded - failed - skipped started_at: type: string format: date-time completed_at: type: string format: date-time duration_seconds: type: integer format: int64 minimum: 0 required: - name - status DeploymentProgress: type: object description: Normalized live progress derived from the deployment workflow and build phases. properties: current_phase: type: string enum: - queue - checkout - build - image - provisioning - rollout - verification started_at: type: string format: date-time completed_at: type: string format: date-time elapsed_seconds: type: integer format: int64 minimum: 0 phases: type: array minItems: 7 maxItems: 7 items: $ref: '#/components/schemas/DeploymentPhase' updated_at: type: string format: date-time required: - started_at - elapsed_seconds - phases - updated_at LogDeploymentRequestSelector: type: object description: Deployment log selector for deployable resources. additionalProperties: false properties: ids: type: array maxItems: 25 description: Optional deployment identifiers. Omit or send an empty array to include every deployment for the selected resources. items: type: string format: uuid LogFunctionRequestResource: type: object description: Edge Function log resource selector. additionalProperties: false properties: type: type: string enum: - function description: Resource type to read logs for. ids: type: array maxItems: 25 description: Optional function identifiers. Omit or send an empty array to include every function in the project. items: type: string format: uuid deployments: $ref: '#/components/schemas/LogDeploymentRequestSelector' required: - type LogFrontendRequestResource: type: object description: Frontend log resource selector. additionalProperties: false properties: type: type: string enum: - frontend description: Resource type to read logs for. ids: type: array maxItems: 25 description: Optional frontend identifiers. Omit or send an empty array to include every frontend in the project. items: type: string format: uuid deployments: $ref: '#/components/schemas/LogDeploymentRequestSelector' required: - type LogDatabaseRequestResource: type: object description: Database runtime log resource selector. Deployment logs are not supported for databases. additionalProperties: false properties: type: type: string enum: - database description: Resource type to read logs for. ids: type: array maxItems: 25 description: Optional database identifiers. Omit or send an empty array to include every database in the project. items: type: string format: uuid required: - type LogRequestResource: description: Resource selectors for project log reads. oneOf: - $ref: '#/components/schemas/LogFunctionRequestResource' - $ref: '#/components/schemas/LogFrontendRequestResource' - $ref: '#/components/schemas/LogDatabaseRequestResource' discriminator: propertyName: type mapping: function: '#/components/schemas/LogFunctionRequestResource' frontend: '#/components/schemas/LogFrontendRequestResource' database: '#/components/schemas/LogDatabaseRequestResource' LogResource: type: object description: Resource that owns a historical log event. properties: type: type: string enum: - function - frontend - database description: Resource type that owns the log event. id: type: string format: uuid description: Resource ID that owns the log event. name: type: string description: Resource name associated with the log event, when available. required: - type - id LogDeployment: type: object description: Deployment context associated with a historical deployment log event. properties: id: type: string format: uuid description: Deployment ID associated with the log event. stage: type: string enum: - compile - publish description: Deployment stage that produced the log event, when available. required: - id DatabaseQueryFilter: type: object description: One WHERE condition. Conditions are combined with AND. properties: column: type: string example: status operator: type: string enum: - eq - neq - gt - gte - lt - lte - like - ilike - is - in example: eq description: | Filter operators: - eq: equals (=) - neq: not equals (<>) - gt: greater than (>) - gte: greater than or equal (>=) - lt: less than (<) - lte: less than or equal (<=) - like: pattern match (LIKE) - ilike: case-insensitive pattern match (ILIKE) - is: IS NULL / IS NOT NULL - in: IN array value: oneOf: - type: string nullable: true - type: number - type: boolean - type: array description: Array of values, for the `in` operator items: oneOf: - type: string - type: number - type: boolean example: published required: - column - operator - value DatabaseQueryOrder: type: object description: One ORDER BY clause. properties: column: type: string example: created_at ascending: type: boolean default: true example: false nulls_first: type: boolean default: false required: - column FunctionRuntimeDeployment: type: object required: - file_extensions - entrypoint - handler - dependency_manifests properties: file_extensions: type: array description: Source file extensions the CLI can use to detect this runtime. items: type: string example: - .js - .mjs entrypoint: type: string description: Archive path the CLI should use for a single-file function source. example: index.js handler: type: string description: Handler symbol the CLI should submit when deploying this runtime. example: handler dependency_manifests: type: array description: Dependency manifest files the CLI should include for hosted builds. items: type: string example: - package.json - package-lock.json AuthHostedPageDefaults: type: object required: - html - css description: | The starting point for an unsaved page: the theme shell we render for the built-in page plus its stylesheet. Valid input to the update endpoint — it carries no script, meta, or link tags. properties: html: type: string description: Body shell markup containing the runtime render root. css: type: string description: The built-in stylesheet, themed by the customer. AuthHostedPageRuntime: type: object required: - root_id - script - mock_prelude description: | The server-owned behavior of a hosted page. Clients compose previews from this instead of reimplementing the page, so a preview cannot drift from what is actually served. properties: root_id: type: string description: Element id the runtime script renders into. Markup carrying it opts into the theme-shell contract. script: type: string description: The runtime script injected into the rendered page. mock_prelude: type: string description: Preview harness that supplies request params and stubs the hosted-auth API. Never served on a real page. AuthPageAppearanceDefaults: type: object required: - theme - layout properties: theme: $ref: '#/components/schemas/AuthPageTheme' layout: $ref: '#/components/schemas/AuthPageLayout' AuthPageAppearanceOptions: type: object required: - pages - fonts - scales - densities - radii - layouts properties: pages: type: array items: $ref: '#/components/schemas/HostedAuthPageType' fonts: type: array items: $ref: '#/components/schemas/AuthPageFont' scales: type: array items: $ref: '#/components/schemas/AuthPageScale' densities: type: array items: $ref: '#/components/schemas/AuthPageDensity' radii: type: array items: $ref: '#/components/schemas/AuthPageRadius' layouts: type: array items: $ref: '#/components/schemas/AuthPageLayout'