{"openapi":"3.1.0","info":{"title":"Microsandbox API","description":"Microsandbox platform API — sandbox orchestration, organizations, and API key management.","license":{"name":"MIT"},"version":"0.1.0"},"paths":{"/admin/v1/billing/credits/grant":{"post":{"tags":["billing"],"summary":"Grant USD credit that Stripe applies to this organization's future invoices.","operationId":"grant_credit","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantAccountCreditRequest"}}},"required":true},"responses":{"200":{"description":"Credit granted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountCreditTransaction"}}}},"400":{"description":"Invalid credit grant"},"401":{"description":"Invalid operator credential"},"404":{"description":"Organization or billing configuration not found"},"502":{"description":"Billing provider unavailable"}},"security":[{"billing_operator":[]}],"x-hidden":true}},"/healthz":{"get":{"tags":["health"],"summary":"Basic liveness probe — returns 200 if the server is running.","operationId":"healthz","responses":{"200":{"description":"Server is alive","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/readyz":{"get":{"tags":["health"],"summary":"Readiness probe — gates on the database plus the startup readiness latch\n(≥1 cluster seen). Ready iff the DB is reachable AND startup has latched; a later\ncluster outage does NOT 503 (lenient) — sandbox-start fails fast on its own, so\ncluster-independent endpoints keep serving. Ongoing cluster health lives in metrics.","operationId":"readyz","responses":{"200":{"description":"All components ready","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadyzResponse"}}}},"503":{"description":"One or more components unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadyzResponse"}}}}}}},"/v1/auth/forgot-password":{"post":{"tags":["auth"],"summary":"POST /v1/auth/forgot-password — send a password reset email.","operationId":"forgot_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent (if registered)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}}}}},"/v1/auth/login":{"post":{"tags":["auth"],"summary":"POST /v1/auth/login — authenticate with email and password.","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful or TOTP required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"401":{"description":"Invalid credentials"},"403":{"description":"Account suspended or unverified"}}}},"/v1/auth/login/2fa":{"post":{"tags":["auth"],"summary":"POST /v1/auth/login/2fa — complete a pending login challenge with TOTP or recovery code.","operationId":"login_two_factor","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginTwoFactorRequest"}}},"required":true},"responses":{"200":{"description":"Login completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid challenge or code"},"401":{"description":"Invalid credentials"}}}},"/v1/auth/logout":{"post":{"tags":["auth"],"summary":"POST /v1/auth/logout — end the current session.","operationId":"logout","responses":{"200":{"description":"Logged out","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/auth/oauth/{provider}":{"get":{"tags":["oauth"],"summary":"GET /v1/auth/oauth/{provider} — initiate OAuth flow.","description":"Generates an authorization URL with PKCE, stores state in DB, and returns\nthe URL for the client to redirect the user to.","operationId":"oauth_initiate","parameters":[{"name":"provider","in":"path","description":"OAuth provider (e.g. github, google)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Authorization URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthInitiateResponse"}}}},"400":{"description":"Unsupported provider"}}}},"/v1/auth/oauth/{provider}/callback":{"get":{"tags":["oauth"],"summary":"GET /v1/auth/oauth/{provider}/callback — handle OAuth provider callback.","description":"Verifies CSRF state, exchanges code for access token, fetches user info,\nfinds or creates the user, links the OAuth provider, and creates a session.","operationId":"oauth_callback","parameters":[{"name":"provider","in":"path","description":"OAuth provider","required":true,"schema":{"type":"string"}},{"name":"code","in":"query","description":"Authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Authenticated or TOTP required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"400":{"description":"Invalid state or code"},"403":{"description":"Account suspended"}}}},"/v1/auth/oidc/{org_slug}":{"get":{"tags":["oidc"],"summary":"GET /v1/auth/oidc/{org_slug} — initiate OIDC SSO for an organization.","description":"Loads the org's OIDC config, performs discovery, generates an authorization\nURL with PKCE + nonce, stores state in DB, and returns the redirect URL.","operationId":"oidc_initiate","parameters":[{"name":"org_slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Authorization URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcInitiateResponse"}}}},"400":{"description":"OIDC disabled"},"404":{"description":"Organization or OIDC config not found"}}}},"/v1/auth/oidc/{org_slug}/callback":{"get":{"tags":["oidc"],"summary":"GET /v1/auth/oidc/{org_slug}/callback — handle OIDC provider callback.","description":"Verifies CSRF state, exchanges code for ID token, validates claims,\nenforces allowed_domains, finds or creates the user, auto-provisions\norg membership if configured, and creates a session.","operationId":"oidc_callback","parameters":[{"name":"org_slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"code","in":"query","description":"Authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Authenticated or TOTP required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"400":{"description":"Invalid state or code"},"403":{"description":"Domain not allowed or account suspended"},"404":{"description":"Organization not found"}}}},"/v1/auth/refresh":{"post":{"tags":["auth"],"summary":"POST /v1/auth/refresh — exchange a refresh token for a new token pair.","operationId":"refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"Tokens refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid or expired refresh token"}}}},"/v1/auth/register":{"post":{"tags":["auth"],"summary":"POST /v1/auth/register — create a new account with email and password.","description":"Returns auth tokens so the user is immediately logged in.\nA verification email is sent; the frontend restricts actions until verified.","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}},"required":true},"responses":{"200":{"description":"Registration successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"Email already registered"}}}},"/v1/auth/reset-password":{"post":{"tags":["auth"],"summary":"POST /v1/auth/reset-password — set a new password using a reset token.","operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid token or weak password"}}}},"/v1/auth/verify-email":{"post":{"tags":["auth"],"summary":"POST /v1/auth/verify-email — verify email address with a purpose token.","operationId":"verify_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid or expired token"}}}},"/v1/billing":{"get":{"tags":["billing"],"summary":"GET /v1/billing — billing summary for the key's org.","operationId":"get_billing","responses":{"200":{"description":"Billing summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSummaryResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]}},"/v1/billing/invoices":{"get":{"tags":["billing"],"summary":"GET /v1/billing/invoices — list invoices for the key's org.","operationId":"list_invoices","responses":{"200":{"description":"Invoice list","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]}},"/v1/billing/invoices/{invoice_id}":{"get":{"tags":["billing"],"summary":"GET /v1/billing/invoices/:invoice_id — get a single invoice.","operationId":"get_invoice","parameters":[{"name":"invoice_id","in":"path","description":"Invoice ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Invoice detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invoice"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Invoice not found"}},"security":[{"api_key":[]}]}},"/v1/billing/plans":{"get":{"tags":["billing"],"summary":"GET /v1/billing/plans — list available billing plans.","operationId":"list_plans","responses":{"200":{"description":"Available plans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BillingPlan"}}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]}},"/v1/billing/usage":{"get":{"tags":["billing"],"summary":"GET /v1/billing/usage — usage summary for the key's org.","description":"Return billable usage for the organization.","operationId":"get_usage","responses":{"200":{"description":"Usage summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]}},"/v1/billing/usage/sandbox":{"get":{"tags":["billing"],"summary":"GET /v1/billing/usage/sandbox — per-sandbox/per-day usage for the key's org.","description":"Return billable usage grouped by sandbox for a selected UTC time range.","operationId":"get_sandbox_breakdown","responses":{"200":{"description":"Per-sandbox / per-day usage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageBreakdown"}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]}},"/v1/billing/usage/storage":{"get":{"tags":["billing"],"summary":"GET /v1/billing/usage/storage — per-volume/per-day storage for the key's org.","description":"Return persistent storage usage grouped by volume for a selected UTC time range.","operationId":"get_storage_breakdown","responses":{"200":{"description":"Per-volume / per-day storage usage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageBreakdown"}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]}},"/v1/events":{"get":{"tags":["audit-log"],"summary":"GET /v1/events — list audit events in the key's org (Admin+). Pinned to\nthe `audit` category like the slug variant.","description":"List audit events for the organization with cursor pagination and optional filters.","operationId":"list_events","parameters":[{"name":"event_type","in":"query","description":"Filter by event type (e.g. \"api_key_created\").","required":false,"schema":{"type":["string","null"]}},{"name":"since","in":"query","description":"Only return events at or after this timestamp.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"until","in":"query","description":"Only return events at or before this timestamp.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"cursor","in":"query","description":"Opaque cursor from a previous response.","required":false,"schema":{"type":["string","null"]}},{"name":"limit","in":"query","description":"Number of items to return (default: 20, max: 100).","required":false,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Paginated list of audit events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]}},"/v1/events/{event_id}":{"get":{"tags":["audit-log"],"summary":"GET /v1/events/:event_id — get a single audit event (Admin+);\nlifecycle events 404.","description":"Retrieve one audit event by its identifier.","operationId":"get_event","parameters":[{"name":"event_id","in":"path","description":"Event ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Event not found"}},"security":[{"api_key":[]}]}},"/v1/invites/{token}/accept":{"post":{"tags":["invites"],"summary":"POST /v1/invites/:token/accept — accept an invite and join the organization.","operationId":"accept_invite","parameters":[{"name":"token","in":"path","description":"Invite token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Invite accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid or expired token"},"401":{"description":"Unauthorized"},"403":{"description":"Email mismatch"}},"security":[{"bearer":[]}]}},"/v1/invites/{token}/decline":{"post":{"tags":["invites"],"summary":"POST /v1/invites/:token/decline — decline an invite.","operationId":"decline_invite","parameters":[{"name":"token","in":"path","description":"Invite token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Invite declined","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid or expired token"},"401":{"description":"Unauthorized"},"403":{"description":"Email mismatch"}},"security":[{"bearer":[]}]}},"/v1/me/org":{"get":{"tags":["organizations"],"summary":"GET /v1/me/org — get the org bound to this API key (Member+).","description":"The slug-prefixed `GET /v1/orgs/:slug` returns the user's role; here the\nkey is treated as `Owner` (matches `OrgContext` semantics), so the\nreturned role is informational rather than a real per-user binding.","operationId":"get_org","responses":{"200":{"description":"Organization bound to this API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgWithRole"}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]}},"/v1/members":{"get":{"tags":["members"],"summary":"GET /v1/members — list members in the key's org (Member+).","description":"List organization members and their roles with cursor pagination.","operationId":"list_members","parameters":[{"name":"cursor","in":"query","description":"Pagination cursor","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]}},"/v1/orgs":{"get":{"tags":["organizations"],"summary":"GET /v1/orgs — list organizations the authenticated user belongs to.","operationId":"list_orgs","responses":{"200":{"description":"User's organizations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrgWithRole"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]},"post":{"tags":["organizations"],"summary":"POST /v1/orgs — create a new organization; the creator becomes owner.","operationId":"create_org","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgRequest"}}},"required":true},"responses":{"200":{"description":"Organization created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"409":{"description":"Slug already taken"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}":{"get":{"tags":["organizations"],"summary":"GET /v1/orgs/:slug — get organization details (Member+).","operationId":"get_org","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Organization details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgWithRole"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Not a member"}},"security":[{"bearer":[]}]},"delete":{"tags":["organizations"],"summary":"DELETE /v1/orgs/:slug — soft-delete an organization (Owner only).","description":"The org drops out of every lookup immediately (inaccessible) but its data is kept\nfor a grace window so the account is recoverable, then a background reconciler\npurges everything. Billing is canceled and running sandboxes are stopped now so we\nstop charging + consuming compute; both are best-effort and re-ensured by the purge\njob. `confirm` must echo the slug (the dashboard's type-to-confirm).","operationId":"delete_org","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteOrgRequest"}}},"required":true},"responses":{"200":{"description":"Organization scheduled for deletion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Confirmation does not match"},"401":{"description":"Unauthorized"},"403":{"description":"Owner role required"}},"security":[{"bearer":[]}]},"patch":{"tags":["organizations"],"summary":"PATCH /v1/orgs/:slug — update organization (Admin+).","operationId":"update_org","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrgRequest"}}},"required":true},"responses":{"200":{"description":"Organization updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/api-keys":{"get":{"tags":["api-keys"],"summary":"GET /v1/orgs/:slug/api-keys — list API keys (Member+).","description":"Admins and owners see all keys. Members see only their own keys.","operationId":"list_api_keys","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Pagination cursor","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of API keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]},"post":{"tags":["api-keys"],"summary":"POST /v1/orgs/:slug/api-keys — generate a new API key (Member+).","description":"The raw key is returned **once** in the response. Only its SHA-256 credential\nfingerprint is used for authentication. The key is owned by the creating user.","operationId":"create_api_key","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"API key created (raw key returned once)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Name already exists"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/orgs/{slug}/api-keys/{api_key_id}":{"delete":{"tags":["api-keys"],"summary":"DELETE /v1/orgs/:slug/api-keys/:id — revoke an API key (Admin+).","operationId":"revoke_api_key","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"api_key_id","in":"path","description":"API key ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"API key revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"API key not found"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/orgs/{slug}/billing":{"get":{"tags":["billing"],"summary":"GET /v1/orgs/:slug/billing — get billing status for an organization.","operationId":"get_billing","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Billing summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Not a member"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/billing/cancel":{"post":{"tags":["billing"],"summary":"POST /v1/orgs/:slug/billing/cancel — cancel the paid subscription at period end (Owner).","operationId":"cancel_subscription","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cancellation scheduled for period end","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/billing/invoices":{"get":{"tags":["billing"],"summary":"GET /v1/orgs/:slug/billing/invoices — list invoices from Metronome.","operationId":"list_invoices","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Invoice list","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/billing/invoices/{invoice_id}":{"get":{"tags":["billing"],"summary":"GET /v1/orgs/:slug/billing/invoices/:invoice_id — get a single invoice.","operationId":"get_invoice","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"invoice_id","in":"path","description":"Invoice ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Invoice detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invoice"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Invoice not found"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/billing/payment-portal":{"get":{"tags":["billing"],"summary":"GET /v1/orgs/:slug/billing/payment-portal — hosted payment-method management.\nReturns the provider's redirect URL (Stripe Checkout / billing-portal); the\nclient sends the user there to add or manage cards (replaces the inline flow).","operationId":"payment_portal","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Payment portal URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentPortalResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/billing/plan":{"put":{"tags":["billing"],"summary":"PUT /v1/orgs/:slug/billing/plan — change billing plan (Admin+).","operationId":"change_plan","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePlanRequest"}}},"required":true},"responses":{"200":{"description":"Plan changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSummaryResponse"}}}},"400":{"description":"Invalid plan or payment method required"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/billing/plans":{"get":{"tags":["billing"],"summary":"GET /v1/orgs/:slug/billing/plans — list available billing plans.","operationId":"list_plans","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Available plans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BillingPlan"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/billing/usage":{"get":{"tags":["billing"],"summary":"GET /v1/orgs/:slug/billing/usage — live cost estimate (subscription +\noverage) for the current period, priced from our own meter.","operationId":"get_usage","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cost estimate for the current period","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/billing/usage/sandbox":{"get":{"tags":["billing"],"summary":"GET /v1/orgs/:slug/billing/usage/sandbox — per-sandbox / per-day compute\nusage over a window (defaults to the current calendar month), computed on\nread from `sandbox_runs`.","operationId":"get_sandbox_breakdown","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Window start (RFC 3339); defaults to month start","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Per-sandbox / per-day usage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageBreakdown"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/billing/usage/storage":{"get":{"tags":["billing"],"summary":"GET /v1/orgs/:slug/billing/usage/storage — per-volume / per-day\ndurable-storage usage over a window (defaults to the current calendar month),\ncomputed on read from `storage_accruals`.","operationId":"get_storage_breakdown","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Window start (RFC 3339); defaults to month start","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Per-volume / per-day storage usage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageBreakdown"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/events":{"get":{"tags":["audit-log"],"summary":"GET /v1/orgs/:slug/events — list audit events (Admin+). Pinned to the\n`audit` category server-side: lifecycle (system/internal) events are never\nreturned here, whatever the query says.","operationId":"list_events","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"event_type","in":"query","description":"Filter by event type (e.g. \"api_key_created\").","required":false,"schema":{"type":["string","null"]}},{"name":"since","in":"query","description":"Only return events at or after this timestamp.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"until","in":"query","description":"Only return events at or before this timestamp.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"cursor","in":"query","description":"Opaque cursor from a previous response.","required":false,"schema":{"type":["string","null"]}},{"name":"limit","in":"query","description":"Number of items to return (default: 20, max: 100).","required":false,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Paginated list of audit events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/events/{event_id}":{"get":{"tags":["audit-log"],"summary":"GET /v1/orgs/:slug/events/:event_id — get a single audit event (Admin+).\nLifecycle events 404 here, same as an unknown id.","operationId":"get_event","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"event_id","in":"path","description":"Event ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Event not found"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/invites":{"get":{"tags":["invites"],"summary":"GET /v1/orgs/:slug/invites — list pending invites for the organization (Admin+).","operationId":"list_invites","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of pending invites","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrgInvite"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]},"post":{"tags":["invites"],"summary":"POST /v1/orgs/:slug/invites — invite a user by email (Admin+).","operationId":"create_invite","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInviteRequest"}}},"required":true},"responses":{"200":{"description":"Invite created or refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgInvite"}}}},"400":{"description":"Invalid email"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"User already a member"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/invites/{invite_id}":{"delete":{"tags":["invites"],"summary":"DELETE /v1/orgs/:slug/invites/:invite_id — cancel a pending invite (Admin+).","operationId":"cancel_invite","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"invite_id","in":"path","description":"Invite ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Invite cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Invite not found"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/members":{"get":{"tags":["members"],"summary":"GET /v1/orgs/:slug/members — list members of the organization (Member+).","operationId":"list_members","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Pagination cursor","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Not a member"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/members/{user_id}":{"delete":{"tags":["members"],"summary":"DELETE /v1/orgs/:slug/members/:user_id — remove a member from the organization (Admin+).","operationId":"remove_member","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"user_id","in":"path","description":"Target user ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Member removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Cannot remove yourself"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer":[]}]},"patch":{"tags":["members"],"summary":"PATCH /v1/orgs/:slug/members/:user_id — update a member's role (Admin+).","operationId":"update_member_role","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"user_id","in":"path","description":"Target user ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMember"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/oidc":{"get":{"tags":["oidc-config"],"summary":"GET /v1/orgs/:slug/oidc — retrieve the organization's OIDC config (Admin+).","operationId":"get_oidc_config","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OIDC configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgOidcConfig"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"OIDC not configured"}},"security":[{"bearer":[]}]},"put":{"tags":["oidc-config"],"summary":"PUT /v1/orgs/:slug/oidc — create or update the OIDC config (Owner only).","operationId":"upsert_oidc_config","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertOidcConfigRequest"}}},"required":true},"responses":{"200":{"description":"OIDC config created or updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgOidcConfig"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]},"delete":{"tags":["oidc-config"],"summary":"DELETE /v1/orgs/:slug/oidc — remove the OIDC config (Owner only).","operationId":"delete_oidc_config","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OIDC config removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"OIDC not configured"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/quotas":{"get":{"tags":["quotas"],"summary":"GET /v1/orgs/:slug/quotas — get quota usage for an organization.","operationId":"get_quotas","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Quota usage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaUsage"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Not a member"},"404":{"description":"Org not found"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/quotas/override":{"put":{"tags":["quotas"],"summary":"PUT /v1/orgs/:slug/quotas/override — set per-org quota overrides (Owner only).","operationId":"set_quota_override","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetQuotaOverrideRequest"}}},"required":true},"responses":{"200":{"description":"Override applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaOverride"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/registries":{"get":{"tags":["registry-credentials"],"summary":"GET /v1/orgs/:slug/registries — list configured registry credentials (Member+).\nNever returns the secret or the vault path.","operationId":"list_registry_credentials","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Configured registry credentials","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RegistryCredentialResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]},"put":{"tags":["registry-credentials"],"summary":"PUT /v1/orgs/:slug/registries — create or update a credential for a host (Admin+).","description":"Writes the secret material to the store first, then records the metadata\npointer, so the DB never references a secret that failed to land.","operationId":"upsert_registry_credential","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertRegistryCredentialRequest"}}},"required":true},"responses":{"200":{"description":"Credential created or updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistryCredentialResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/registries/{id}":{"delete":{"tags":["registry-credentials"],"summary":"DELETE /v1/orgs/:slug/registries/:id — remove a credential (Admin+).\nDeletes the metadata row, then purges the secret from the store.","operationId":"delete_registry_credential","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","description":"Registry credential id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Credential removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Credential not found"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/sandbox-slug/check":{"get":{"tags":["sandboxes"],"summary":"GET /v1/orgs/:slug/sandbox-slug/check?sandbox_slug=… — validate a candidate\nslug's format and global availability before create (Member+).","operationId":"check_slug","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"sandbox_slug","in":"query","description":"Candidate slug to validate + check. Named `sandbox_slug` in the query to\ndisambiguate from the org `:slug` route param.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Slug validity + availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlugAvailability"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/sandbox-slug/suggest":{"get":{"tags":["sandboxes"],"summary":"GET /v1/orgs/:slug/sandbox-slug/suggest — a fresh, currently-available\nslug to prefill the create form (Member+). Generated and confirmed free.","operationId":"suggest_slug","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"A suggested available slug","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlugSuggestion"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/sandboxes":{"get":{"tags":["sandboxes"],"summary":"GET /v1/orgs/:slug/sandboxes — list sandboxes for an org.","operationId":"list_sandboxes","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Pagination cursor","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"labels","in":"query","description":"JSON object of labels to AND-match","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Not a member"}},"security":[{"bearer":[]}]},"post":{"tags":["sandboxes"],"summary":"POST /v1/orgs/:slug/sandboxes — create a new sandbox definition.","description":"By default only persists the record (status = `created`).\nPass `?start=true` to also queue the job for orchestrator dispatch. Add\n`wait_for=running` to hold the response until the sandbox becomes usable or\nthe bounded wait expires.","operationId":"create_sandbox","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"start","in":"query","description":"If `true`, durably queue the sandbox for immediate orchestrator dispatch.","required":false,"schema":{"type":"boolean"}},{"name":"wait_for","in":"query","description":"Optional lifecycle state to wait for after durable start admission.","required":false,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SandboxWaitFor"}]}},{"name":"wait_timeout","in":"query","description":"Server-side wait budget in seconds; valid only with `wait_for`.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxRequest"}}},"required":true},"responses":{"200":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"409":{"description":"Name already exists"},"429":{"description":"Readiness wait capacity exhausted"},"502":{"description":"Orchestrator unreachable"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/sandboxes/{sandbox_id}":{"get":{"tags":["sandboxes"],"summary":"GET /v1/orgs/:slug/sandboxes/:id — get a specific sandbox.","operationId":"get_sandbox","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"}},"security":[{"bearer":[]}]},"delete":{"tags":["sandboxes"],"summary":"DELETE /v1/orgs/:slug/sandboxes/:id — destroy a sandbox (stop if running, then delete).","operationId":"delete_sandbox","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Sandbox destroyed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"502":{"description":"Sandbox orchestrator unreachable"}},"security":[{"bearer":[]}]},"patch":{"tags":["sandboxes"],"summary":"PATCH /v1/orgs/:slug/sandboxes/:id — rename a sandbox (name and/or slug).","operationId":"update_sandbox","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSandboxRequest"}}},"required":true},"responses":{"200":{"description":"Updated sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid name/slug"},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"409":{"description":"Name or slug already taken"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/sandboxes/{sandbox_id}/metrics":{"get":{"tags":["sandboxes"],"summary":"GET /v1/orgs/:slug/sandboxes/:id/metrics — per-sandbox resource metrics.","description":"CPU / memory / disk / network for one sandbox over a time window, queried\nfrom the Prometheus/Mimir backend. See `plans/monitoring-plan.md` § B.","operationId":"get_metrics","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"range_secs","in":"query","description":"Look-back window in seconds (default 3600 = 1h, max 604800 = 7d).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"step_secs","in":"query","description":"Sample resolution in seconds (default 30, min 5).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Sandbox metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxMetricsResponse"}}}},"400":{"description":"Invalid range/step"},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"502":{"description":"Metrics backend unavailable"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/sandboxes/{sandbox_id}/start":{"post":{"tags":["sandboxes"],"summary":"POST /v1/orgs/:slug/sandboxes/:id/start — start a created, stopped, or failed sandbox.","operationId":"start_sandbox","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"wait_for","in":"query","description":"Optional lifecycle state to wait for after durable start admission.","required":false,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SandboxWaitFor"}]}},{"name":"wait_timeout","in":"query","description":"Server-side wait budget in seconds; valid only with `wait_for`.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Sandbox start admitted or requested wait completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"409":{"description":"Invalid state transition"},"429":{"description":"Readiness wait capacity exhausted"},"502":{"description":"Orchestrator unreachable"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/sandboxes/{sandbox_id}/stop":{"post":{"tags":["sandboxes"],"summary":"POST /v1/orgs/:slug/sandboxes/:id/stop — stop a running sandbox.","operationId":"stop_sandbox","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Sandbox stopping","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"409":{"description":"Invalid state transition"},"502":{"description":"Sandbox orchestrator unreachable"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/sandboxes/{sandbox_id}/volumes":{"get":{"tags":["sandboxes"],"summary":"GET /v1/orgs/:slug/sandboxes/:id/volumes — resolved volume bindings.","operationId":"list_volumes","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Mounted volumes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SandboxVolumeMount"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/volumes":{"get":{"tags":["volumes"],"summary":"GET /v1/orgs/:slug/volumes — list the org's volumes (Member+).","operationId":"list_volumes","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The org's volumes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VolumeResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer":[]}]},"post":{"tags":["volumes"],"summary":"POST /v1/orgs/:slug/volumes — create a named volume (Admin+).","operationId":"create_volume","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVolumeRequest"}}},"required":true},"responses":{"200":{"description":"Volume created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolumeResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Volume name already in use"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/volumes/default":{"get":{"tags":["volumes"],"operationId":"get_default","responses":{},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/volumes/{id}":{"delete":{"tags":["volumes"],"summary":"DELETE /v1/orgs/:slug/volumes/:id — schedule a volume for deletion (Admin+).","operationId":"delete_volume","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","description":"Volume id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Volume scheduled for deletion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Volume not found"},"409":{"description":"The host volume cannot be deleted, or it is in use by a sandbox"}},"security":[{"bearer":[]}]},"patch":{"tags":["volumes"],"summary":"PATCH /v1/orgs/:slug/volumes/:id — set or clear a volume's storage cap (Admin+).","operationId":"update_volume","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","description":"Volume id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVolumeRequest"}}},"required":true},"responses":{"200":{"description":"Volume updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolumeResponse"}}}},"400":{"description":"Invalid request (e.g. cap exceeds the org cap)"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Volume not found"},"409":{"description":"The host volume cannot be capped"}},"security":[{"bearer":[]}]}},"/v1/orgs/{slug}/volumes/{id}/metrics":{"get":{"tags":["volumes"],"summary":"GET /v1/orgs/:slug/volumes/:id/metrics — per-volume JuiceFS performance.","operationId":"get_metrics","parameters":[{"name":"slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","description":"Volume id","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"range_secs","in":"query","description":"Look-back window in seconds (default 3600 = 1h, max 604800 = 7d).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"step_secs","in":"query","description":"Sample resolution in seconds (default 30, min 5).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Volume performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolumeMetricsResponse"}}}},"400":{"description":"Invalid time range or resolution"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Volume not found"},"502":{"description":"Metrics backend unavailable"}},"security":[{"bearer":[]}]}},"/v1/quotas":{"get":{"tags":["quotas"],"summary":"GET /v1/quotas — quota usage for the key's org.","description":"Return current resource usage, plan limits, and organization-specific quota overrides.","operationId":"get_quotas","responses":{"200":{"description":"Quota usage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaUsage"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Org not found"}},"security":[{"api_key":[]}]}},"/v1/sandboxes":{"get":{"tags":["sandboxes"],"summary":"GET /v1/sandboxes — list sandboxes (API key, org inferred from key).","description":"List the organization's sandboxes with cursor pagination and optional label filtering.","operationId":"list_sandboxes","parameters":[{"name":"cursor","in":"query","description":"Pagination cursor","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"labels","in":"query","description":"JSON object of labels to AND-match","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]},"post":{"tags":["sandboxes"],"summary":"POST /v1/sandboxes — create a sandbox (API key, org inferred from key).","description":"Create a microVM sandbox for the organization associated with the API key.","operationId":"create_sandbox","parameters":[{"name":"start","in":"query","description":"If `true`, durably queue the sandbox for immediate orchestrator dispatch.","required":false,"schema":{"type":"boolean"}},{"name":"wait_for","in":"query","description":"Optional lifecycle state to wait for after durable start admission.","required":false,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SandboxWaitFor"}]}},{"name":"wait_timeout","in":"query","description":"Server-side wait budget in seconds; valid only with `wait_for`.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxRequest"}}},"required":true},"responses":{"200":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"409":{"description":"Name already exists"},"429":{"description":"Readiness wait capacity exhausted"},"502":{"description":"Orchestrator unreachable"}},"security":[{"api_key":[]}]}},"/v1/sandboxes/by-name/{name}":{"get":{"tags":["sandboxes"],"summary":"GET /v1/sandboxes/by-name/:name — get a sandbox by name (API key, org inferred from key).","description":"Retrieve one sandbox by its organization-scoped name.","operationId":"get_by_name","parameters":[{"name":"name","in":"path","description":"Sandbox name (unique within the org)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"}},"security":[{"api_key":[]}]},"delete":{"tags":["sandboxes"],"summary":"DELETE /v1/sandboxes/by-name/:name — destroy a sandbox by name (API key).","description":"Stop and permanently destroy a sandbox selected by its organization-scoped name.","operationId":"delete_by_name","parameters":[{"name":"name","in":"path","description":"Sandbox name (unique within the org)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox destroyed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"502":{"description":"Orchestrator unreachable"}},"security":[{"api_key":[]}]}},"/v1/sandboxes/by-name/{name}/start":{"post":{"tags":["sandboxes"],"summary":"POST /v1/sandboxes/by-name/:name/start — start a sandbox by name (API key).","description":"Start a sandbox selected by its organization-scoped name.","operationId":"start_by_name","parameters":[{"name":"name","in":"path","description":"Sandbox name (unique within the org)","required":true,"schema":{"type":"string"}},{"name":"wait_for","in":"query","description":"Optional lifecycle state to wait for after durable start admission.","required":false,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SandboxWaitFor"}]}},{"name":"wait_timeout","in":"query","description":"Server-side wait budget in seconds; valid only with `wait_for`.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Sandbox start admitted or requested wait completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"409":{"description":"Invalid state transition"},"429":{"description":"Readiness wait capacity exhausted"},"502":{"description":"Orchestrator unreachable"}},"security":[{"api_key":[]}]}},"/v1/sandboxes/by-name/{name}/stop":{"post":{"tags":["sandboxes"],"summary":"POST /v1/sandboxes/by-name/:name/stop — stop a sandbox by name (API key).","description":"Stop a running sandbox selected by its organization-scoped name.","operationId":"stop_by_name","parameters":[{"name":"name","in":"path","description":"Sandbox name (unique within the org)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox stopping","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"409":{"description":"Invalid state transition"},"502":{"description":"Orchestrator unreachable"}},"security":[{"api_key":[]}]}},"/v1/sandboxes/{sandbox_id}":{"get":{"tags":["sandboxes"],"summary":"GET /v1/sandboxes/:id — get a sandbox (API key, org inferred from key).","description":"Retrieve one sandbox by its unique identifier.","operationId":"get_sandbox","parameters":[{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"}},"security":[{"api_key":[]}]},"delete":{"tags":["sandboxes"],"summary":"DELETE /v1/sandboxes/:id — destroy a sandbox (API key, org inferred from key).","description":"Stop and permanently destroy a sandbox.","operationId":"delete_sandbox","parameters":[{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Sandbox destroyed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"502":{"description":"Sandbox orchestrator unreachable"}},"security":[{"api_key":[]}]},"patch":{"tags":["sandboxes"],"summary":"PATCH /v1/sandboxes/:id — rename a sandbox (API key, org inferred from key).","description":"Rename a sandbox by updating its display name or slug.","operationId":"update_sandbox","parameters":[{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSandboxRequest"}}},"required":true},"responses":{"200":{"description":"Updated sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid name/slug"},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"409":{"description":"Name or slug already taken"}},"security":[{"api_key":[]}]}},"/v1/sandboxes/{sandbox_id}/metrics":{"get":{"tags":["sandboxes"],"summary":"GET /v1/sandboxes/:id/metrics — per-sandbox metrics (API key, org\ninferred from key).","operationId":"get_metrics","parameters":[{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"range_secs","in":"query","description":"Look-back window in seconds (default 3600 = 1h, max 604800 = 7d).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"step_secs","in":"query","description":"Sample resolution in seconds (default 30, min 5).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Sandbox metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxMetricsResponse"}}}},"400":{"description":"Invalid range/step"},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"502":{"description":"Metrics backend unavailable"}},"security":[{"api_key":[]}]}},"/v1/sandboxes/{sandbox_id}/start":{"post":{"tags":["sandboxes"],"summary":"POST /v1/sandboxes/:id/start — start a sandbox (API key, org inferred from key).","description":"Start a sandbox and optionally wait until it is running.","operationId":"start_sandbox","parameters":[{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"wait_for","in":"query","description":"Optional lifecycle state to wait for after durable start admission.","required":false,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SandboxWaitFor"}]}},{"name":"wait_timeout","in":"query","description":"Server-side wait budget in seconds; valid only with `wait_for`.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Sandbox start admitted or requested wait completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"409":{"description":"Invalid state transition"},"429":{"description":"Readiness wait capacity exhausted"},"502":{"description":"Orchestrator unreachable"}},"security":[{"api_key":[]}]}},"/v1/sandboxes/{sandbox_id}/stop":{"post":{"tags":["sandboxes"],"summary":"POST /v1/sandboxes/:id/stop — stop a sandbox (API key, org inferred from key).","description":"Stop a running sandbox.","operationId":"stop_sandbox","parameters":[{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Sandbox stopping","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"},"409":{"description":"Invalid state transition"},"502":{"description":"Sandbox orchestrator unreachable"}},"security":[{"api_key":[]}]}},"/v1/sandboxes/{sandbox_id}/volumes":{"get":{"tags":["sandboxes"],"summary":"GET /v1/sandboxes/:id/volumes — mounted volumes (API key, org inferred).","operationId":"list_volumes","parameters":[{"name":"sandbox_id","in":"path","description":"Sandbox ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Mounted volumes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SandboxVolumeMount"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Sandbox not found"}},"security":[{"api_key":[]}]}},"/v1/users/me":{"get":{"tags":["users"],"summary":"GET /v1/users/me — return the current authenticated user.","operationId":"get_me","responses":{"200":{"description":"Current user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]},"delete":{"tags":["users"],"summary":"DELETE /v1/users/me — soft-delete the current user (GDPR right-to-be-forgotten).","description":"The user's PII (email, name, password hash, MFA secret, avatar) is cleared\nand the row is tombstoned with `deleted_at`. Sessions are invalidated, org\nmemberships removed, and pending invites issued by this user revoked. Audit\nevents are preserved.\n\nRequires fresh credential proof: the current password (password-backed\naccounts) or a TOTP code (MFA-enabled accounts). At least one must be\nsupplied; both being valid is fine but a single matching proof is enough.\n\nReturns `409 Conflict` if the user is the sole owner of an organization —\nownership must be transferred first.","operationId":"delete_me","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteMeRequest"}}},"required":true},"responses":{"200":{"description":"Account deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Missing credential proof"},"401":{"description":"Invalid password or MFA code"},"409":{"description":"Sole owner of an organization"}},"security":[{"bearer":[]}]},"patch":{"tags":["users"],"summary":"PATCH /v1/users/me — update display name or avatar.","operationId":"update_me","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeRequest"}}},"required":true},"responses":{"200":{"description":"Profile updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]}},"/v1/users/me/change-password":{"post":{"tags":["users"],"summary":"POST /v1/users/me/change-password — change password (requires current password).","operationId":"change_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Weak password or no password set"},"401":{"description":"Invalid current password"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/users/me/mfa/confirm":{"post":{"tags":["users"],"summary":"POST /v1/users/me/mfa/confirm — verify setup and return recovery codes.","operationId":"confirm","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaConfirmRequest"}}},"required":true},"responses":{"200":{"description":"MFA enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecoveryCodesResponse"}}}},"400":{"description":"Invalid code or missing setup"},"401":{"description":"Unauthorized"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/users/me/mfa/recovery-codes":{"post":{"tags":["users"],"summary":"POST /v1/users/me/mfa/recovery-codes — rotate recovery codes after second-factor proof.","operationId":"rotate_recovery_codes","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotateRecoveryCodesRequest"}}},"required":true},"responses":{"200":{"description":"Recovery codes rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecoveryCodesResponse"}}}},"400":{"description":"Invalid proof"},"401":{"description":"Unauthorized"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/users/me/mfa/setup":{"post":{"tags":["users"],"summary":"POST /v1/users/me/mfa/setup — create or replace a pending MFA secret.","operationId":"setup","responses":{"200":{"description":"MFA setup initialized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaSetupResponse"}}}},"400":{"description":"Already enabled"},"401":{"description":"Unauthorized"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/users/me/mfa/status":{"get":{"tags":["users"],"summary":"GET /v1/users/me/mfa/status — fetch MFA enrollment state.","operationId":"get_status","responses":{"200":{"description":"MFA status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaStatusResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/users/me/pats":{"get":{"tags":["personal-access-tokens"],"summary":"GET /v1/users/me/pats — list the current user's active PATs.","description":"Returns metadata only (`id`, `name`, `prefix`, timestamps). Raw token and\nhash are never exposed.","operationId":"list_pats","responses":{"200":{"description":"Active PATs for the current user","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PersonalAccessTokenResponse"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}]},"post":{"tags":["personal-access-tokens"],"summary":"POST /v1/users/me/pats — mint a new personal access token (session-auth only).","description":"The raw token is returned **once** in the response. Only its SHA-256 hash\nplus a short display prefix are persisted. PATs act as the authenticated\nuser across the platform — they cannot be created by other PATs to keep\nthe trust root anchored at a verified browser session, matching\nGitHub/Stripe semantics.","operationId":"create_pat","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePersonalAccessTokenRequest"}}},"required":true},"responses":{"200":{"description":"PAT created (raw token returned once)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePersonalAccessTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"PATs cannot mint other PATs"}},"security":[{"bearer":[]}]}},"/v1/users/me/pats/{id}":{"delete":{"tags":["personal-access-tokens"],"summary":"DELETE /v1/users/me/pats/:id — revoke a PAT (soft-delete via `revoked_at`).","description":"Idempotent on a single token id: re-revoking a missing or already-revoked\nPAT returns 404. The row is preserved for audit history.","operationId":"revoke_pat","parameters":[{"name":"id","in":"path","description":"PAT id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"PAT revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"PAT not found"}},"security":[{"bearer":[]}]}},"/v1/users/me/sessions":{"get":{"tags":["users"],"summary":"GET /v1/users/me/sessions — list all active sessions for the current user.","operationId":"list_sessions","responses":{"200":{"description":"Active sessions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserSession"}}}}},"401":{"description":"Unauthorized"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/users/me/sessions/{id}":{"delete":{"tags":["users"],"summary":"DELETE /v1/users/me/sessions/:id — revoke a specific session.","operationId":"delete_session","parameters":[{"name":"id","in":"path","description":"Session ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Session revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Session not found"}},"security":[{"session":[]}],"x-hidden":true}},"/v1/volumes":{"get":{"tags":["volumes"],"summary":"GET /v1/volumes — list volumes (API key, org inferred from key).","description":"List persistent volumes available to the organization, including current usage.","operationId":"list_volumes","responses":{"200":{"description":"The org's volumes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VolumeResponse"}}}}},"401":{"description":"Unauthorized"}},"security":[{"api_key":[]}]},"post":{"tags":["volumes"],"summary":"POST /v1/volumes — create a named volume (API key, org inferred from key).","description":"Create a named persistent volume with optional capacity and labels.","operationId":"create_volume","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVolumeRequest"}}},"required":true},"responses":{"200":{"description":"Volume created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolumeResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"409":{"description":"Volume name already in use"}},"security":[{"api_key":[]}]}},"/v1/volumes/default":{"get":{"tags":["volumes"],"operationId":"get_default","responses":{},"security":[{"api_key":[]}]}},"/v1/volumes/{id}":{"delete":{"tags":["volumes"],"summary":"DELETE /v1/volumes/:id — schedule a volume for deletion (API key, org\ninferred from key).","description":"Schedule an unused named volume for deletion.","operationId":"delete_volume","parameters":[{"name":"id","in":"path","description":"Volume id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Volume scheduled for deletion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Volume not found"},"409":{"description":"The default volume cannot be deleted"}},"security":[{"api_key":[]}]},"patch":{"tags":["volumes"],"summary":"PATCH /v1/volumes/:id — set or clear a volume's storage cap (API key, org\ninferred from key).","description":"Update a named volume's capacity limit or labels.","operationId":"update_volume","parameters":[{"name":"id","in":"path","description":"Volume id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVolumeRequest"}}},"required":true},"responses":{"200":{"description":"Volume updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolumeResponse"}}}},"400":{"description":"Invalid request (e.g. cap exceeds the org cap)"},"401":{"description":"Unauthorized"},"404":{"description":"Volume not found"},"409":{"description":"The host volume cannot be capped"}},"security":[{"api_key":[]}]}},"/v1/volumes/{id}/files":{"get":{"tags":["volumes"],"operationId":"list","parameters":[{"name":"id","in":"path","description":"Volume UUID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-msb-file-path","in":"header","description":"URL-safe base64 encoded volume-relative UTF-8 path","required":true,"schema":{"type":"string"}}],"responses":{},"security":[{"api_key":[]}]},"delete":{"tags":["volumes"],"operationId":"remove","parameters":[{"name":"id","in":"path","description":"Volume UUID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-msb-file-path","in":"header","description":"URL-safe base64 encoded volume-relative UTF-8 path","required":true,"schema":{"type":"string"}},{"name":"x-msb-file-recursive","in":"header","description":"Recursively remove a directory","required":false,"schema":{"type":["boolean","null"]}}],"responses":{},"security":[{"api_key":[]}]}},"/v1/volumes/{id}/files/content":{"get":{"tags":["volumes"],"operationId":"read","parameters":[{"name":"id","in":"path","description":"Volume UUID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-msb-file-path","in":"header","description":"URL-safe base64 encoded volume-relative UTF-8 path","required":true,"schema":{"type":"string"}}],"responses":{},"security":[{"api_key":[]}]},"put":{"tags":["volumes"],"operationId":"write","parameters":[{"name":"id","in":"path","description":"Volume UUID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-msb-file-path","in":"header","description":"URL-safe base64 encoded volume-relative UTF-8 path","required":true,"schema":{"type":"string"}}],"responses":{},"security":[{"api_key":[]}]}},"/v1/volumes/{id}/files/copy":{"post":{"tags":["volumes"],"operationId":"copy","parameters":[{"name":"id","in":"path","description":"Volume UUID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileMoveRequest"}}},"required":true},"responses":{},"security":[{"api_key":[]}]}},"/v1/volumes/{id}/files/exists":{"get":{"tags":["volumes"],"operationId":"exists","parameters":[{"name":"id","in":"path","description":"Volume UUID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-msb-file-path","in":"header","description":"URL-safe base64 encoded volume-relative UTF-8 path","required":true,"schema":{"type":"string"}}],"responses":{},"security":[{"api_key":[]}]}},"/v1/volumes/{id}/files/mkdir":{"post":{"tags":["volumes"],"operationId":"mkdir","parameters":[{"name":"id","in":"path","description":"Volume UUID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FilePathRequest"}}},"required":true},"responses":{},"security":[{"api_key":[]}]}},"/v1/volumes/{id}/files/rename":{"post":{"tags":["volumes"],"operationId":"rename","parameters":[{"name":"id","in":"path","description":"Volume UUID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileMoveRequest"}}},"required":true},"responses":{},"security":[{"api_key":[]}]}},"/v1/volumes/{id}/files/stat":{"get":{"tags":["volumes"],"operationId":"stat","parameters":[{"name":"id","in":"path","description":"Volume UUID","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-msb-file-path","in":"header","description":"URL-safe base64 encoded volume-relative UTF-8 path","required":true,"schema":{"type":"string"}}],"responses":{},"security":[{"api_key":[]}]}},"/v1/volumes/{id}/metrics":{"get":{"tags":["volumes"],"summary":"GET /v1/volumes/:id/metrics — per-volume JuiceFS performance (API key).","operationId":"get_metrics","parameters":[{"name":"id","in":"path","description":"Volume id","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"range_secs","in":"query","description":"Look-back window in seconds (default 3600 = 1h, max 604800 = 7d).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"step_secs","in":"query","description":"Sample resolution in seconds (default 30, min 5).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Volume performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolumeMetricsResponse"}}}},"400":{"description":"Invalid time range or resolution"},"401":{"description":"Unauthorized"},"404":{"description":"Volume not found"},"502":{"description":"Metrics backend unavailable"}},"security":[{"api_key":[]}]}},"/v1/waitlist":{"post":{"tags":["waitlist"],"summary":"POST /v1/waitlist — public request-access endpoint (landing form + the\nsignup form's one-click request). Idempotent; reveals nothing about\nexisting entries or approval state.","operationId":"join_waitlist","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinWaitlistRequest"}}},"required":true},"responses":{"200":{"description":"Request recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Invalid email"}}}}},"components":{"schemas":{"AccountCreditTransaction":{"type":"object","description":"Stripe's immutable customer-balance transaction, normalized as positive credit.","required":["id","stripe_customer_id","amount_cents","available_credit_cents","currency","created_at"],"properties":{"amount_cents":{"type":"integer","format":"int32","minimum":0},"available_credit_cents":{"type":"integer","format":"int64","minimum":0},"created_at":{"type":"string","format":"date-time"},"currency":{"type":"string"},"id":{"type":"string"},"stripe_customer_id":{"type":"string"}}},"Action":{"type":"string","description":"Action to take on traffic matched by a [`Rule`] (or a policy default).","enum":["allow","deny"]},"ApiKeyResponse":{"type":"object","description":"API key metadata returned in list responses. Never includes the raw key or hashes.","required":["id","name","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"AuthResponse":{"type":"object","description":"Successful auth response (login, register, refresh).","required":["access_token","refresh_token","expires_in"],"properties":{"access_token":{"type":"string"},"expires_in":{"type":"integer","format":"int64","description":"Access token TTL in seconds."},"refresh_token":{"type":"string"}}},"BillingEffectiveState":{"type":"string","description":"Effective billing state derived from plan, period end, and suspension.","enum":["free","active","past_due","suspended"]},"BillingPlan":{"type":"object","description":"Billing plan definition with resource quotas.\n\n`name` is the plan's identity, an arbitrary catalog string (no fixed enum) —\n\"free\"/\"builder\"/… are just the names we ship. Every quota is `Option`:\n`None` = unlimited (counts/budgets) or the system/node max (per-sandbox\nvcpu/memory/disk). There is no magic 0.","required":["id","name","display_name","self_serve","is_default","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"description":{"type":["string","null"]},"display_name":{"type":"string"},"id":{"type":"string","format":"uuid"},"included_disk_gib_hours":{"type":["integer","null"],"format":"int32"},"included_memory_gib_hours":{"type":["integer","null"],"format":"int32"},"included_storage_gib":{"type":["integer","null"],"format":"int32"},"included_vcpu_hours":{"type":["integer","null"],"format":"int32","description":"Monthly included allowances bundled into the flat fee (pool of vCPU-hours /\nmemory GiB-hours / writable-disk GiB-hours / durable-storage GiB). Usage\nbeyond the pool is metered overage on priced plans; on an unpriced (free)\nplan the compute pool is a hard wall."},"is_default":{"type":"boolean","description":"The plan new orgs are assigned. Exactly one row is the default."},"max_concurrent_ephemeral_running":{"type":["integer","null"],"format":"int32","description":"Max simultaneously-running *ephemeral* sandboxes (cheap, self-cleaning)."},"max_concurrent_persistent_running":{"type":["integer","null"],"format":"int32","description":"Max simultaneously-running *persistent* sandboxes (snapshot/restore cost)."},"max_disk_size_mib_per_sandbox":{"type":["integer","null"],"format":"int32","description":"Maximum writable disk size (MiB) per sandbox."},"max_memory_mib_per_sandbox":{"type":["integer","null"],"format":"int32"},"max_sandboxes":{"type":["integer","null"],"format":"int32"},"max_total_storage_gib":{"type":["integer","null"],"format":"int32","description":"Per-org durable-storage hard cap (GiB). Used storage is billed at a flat\nper-GB-month rate (no free allotment)."},"max_uptime_minutes_per_sandbox":{"type":["integer","null"],"format":"int32"},"max_vcpus_per_sandbox":{"type":["integer","null"],"format":"int32"},"monthly_sandbox_minutes":{"type":["integer","null"],"format":"int32","description":"Deprecated wall-clock minutes budget (NULL). The compute wall is now\n`included_vcpu_hours` on unpriced plans."},"name":{"type":"string"},"self_serve":{"type":"boolean","description":"May a user self-subscribe to this plan via the API? Fail-closed; the\nchange-plan check keys on this flag, not the plan name."},"subscription_price_cents":{"type":["integer","null"],"format":"int64","description":"Flat monthly subscription price (cents); `None` = unpriced (free). Source\nof upgrade/downgrade ordering — compare prices, not a fixed tier rank."},"trial_duration_days":{"type":["integer","null"],"format":"int32"},"updated_at":{"type":"string","format":"date-time"},"usage_disk_gib_hour_usd":{"type":["number","null"],"format":"double"},"usage_memory_gib_hour_usd":{"type":["number","null"],"format":"double"},"usage_storage_gib_month_usd":{"type":["number","null"],"format":"double"},"usage_vcpu_hour_usd":{"type":["number","null"],"format":"double","description":"Per-unit overage rates (USD) charged on usage beyond the included pool;\n`None` on the free/unpriced plan (no overage path). Drive the live cost\nestimate `subscription + Σ overage`; Autumn's invoice stays authoritative."}}},"BillingPlanSummary":{"type":"object","description":"Summary of a billing plan (subset of full plan).","required":["name","display_name","has_custom_billing_terms"],"properties":{"display_name":{"type":"string"},"has_custom_billing_terms":{"type":"boolean"},"name":{"type":"string"}}},"BillingPricingTerms":{"type":"object","description":"Pricing fields which may be inherited from a plan or negotiated per customer.","properties":{"included_disk_gib_hours":{"type":["integer","null"],"format":"int32"},"included_memory_gib_hours":{"type":["integer","null"],"format":"int32"},"included_storage_gib":{"type":["integer","null"],"format":"int32"},"included_vcpu_hours":{"type":["integer","null"],"format":"int32"},"subscription_price_cents":{"type":["integer","null"],"format":"int64"},"usage_disk_gib_hour_usd":{"type":["number","null"],"format":"double"},"usage_memory_gib_hour_usd":{"type":["number","null"],"format":"double"},"usage_storage_gib_month_usd":{"type":["number","null"],"format":"double"},"usage_vcpu_hour_usd":{"type":["number","null"],"format":"double"}}},"BillingSummaryResponse":{"type":"object","description":"Billing summary response for an organization.","required":["plan","effective_pricing","effective_state","is_suspended"],"properties":{"available_credit_cents":{"type":["integer","null"],"format":"int64","description":"Positive USD credit Stripe will apply automatically to future invoices.","minimum":0},"billing_terms_override":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BillingTermsOverrideSummary","description":"Current agreement metadata, including setup and payment-pending states."}]},"checkout_url":{"type":["string","null"],"description":"Hosted-checkout URL to complete payment for a just-changed plan (Autumn).\nSet only on a plan change that needs payment; the client redirects to it."},"current_period_ends_at":{"type":["string","null"],"format":"date-time"},"effective_pricing":{"$ref":"#/components/schemas/BillingPricingTerms","description":"Effective commercial terms after applying any org-specific agreement."},"effective_state":{"$ref":"#/components/schemas/BillingEffectiveState"},"is_suspended":{"type":"boolean"},"pending_plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BillingPlanSummary","description":"Plan the org will switch to at `current_period_ends_at`, if a downgrade is scheduled."}]},"plan":{"$ref":"#/components/schemas/BillingPlanSummary"}}},"BillingTermsOverrideSummary":{"type":"object","description":"Effective window for the org's active negotiated billing terms.","required":["status","plan","effective_from"],"properties":{"effective_from":{"type":"string","format":"date-time"},"effective_until":{"type":["string","null"],"format":"date-time"},"plan":{"$ref":"#/components/schemas/BillingPlanSummary"},"post_expiry_plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BillingPlanSummary","description":"Explicit plan assigned at expiry; absent means target-plan retail pricing."}]},"status":{"$ref":"#/components/schemas/OrgBillingTermsOverrideStatus"}}},"CertCacheConfig":{"type":"object","description":"Per-domain certificate cache configuration.","properties":{"capacity":{"type":"integer","description":"Maximum number of cached certificates. Default: 1000.","minimum":0},"validity_hours":{"type":"integer","format":"int64","description":"Certificate validity duration in hours. Default: 24.","minimum":0}}},"ChangePasswordRequest":{"type":"object","description":"POST /v1/users/me/change-password","required":["current_password","new_password"],"properties":{"current_password":{"type":"string"},"new_password":{"type":"string"}}},"ChangePlanRequest":{"type":"object","description":"PUT /v1/orgs/:slug/billing/plan — change billing plan.","required":["plan"],"properties":{"plan":{"type":"string","description":"Catalog name of the plan to switch to (e.g. \"builder\")."}}},"CloudCreateSandboxRequest":{"allOf":[{"$ref":"#/components/schemas/CloudSandboxSpec","description":"The cloud sandbox specification, flattened onto the request body."}],"description":"Wire shape of a cloud sandbox create request body.\n\nFlattens [`CloudSandboxSpec`] onto the request body, so on the wire this is\nbyte-identical to `CloudSandboxSpec`. The generated bindings surface the\nflattened shape as `CloudSandboxSpec` directly."},"CloudDiskImageFormat":{"type":"string","description":"Disk image format for cloud disk-image sources. Twin of [`DiskImageFormat`]\nwith a snake_case wire.","enum":["qcow2","raw","vmdk"]},"CloudHostPattern":{"oneOf":[{"type":"object","description":"Exact hostname match.","required":["value","type"],"properties":{"type":{"type":"string","enum":["exact"]},"value":{"type":"string","description":"Hostname to match exactly."}}},{"type":"object","description":"Wildcard match (e.g. `*.openai.com`).","required":["value","type"],"properties":{"type":{"type":"string","enum":["wildcard"]},"value":{"type":"string","description":"Wildcard pattern."}}},{"type":"object","description":"Any host (dangerous — the secret can be exfiltrated).","required":["type"],"properties":{"type":{"type":"string","enum":["any"]}}}],"description":"Host allowlist pattern for cloud secrets. Twin of [`HostPattern`], with the\ndomain's scalar variants normalized to `{ value }` for a uniform union."},"CloudNetworkSpec":{"type":"object","description":"Cloud network specification: a subset of the domain [`NetworkSpec`].\nInterface overrides, host port mapping, DNS, TLS interception, rate limits,\nand host-CA trust are not part of this type. `deny_unknown_fields` — posting\nan omitted field is an error, not a silent drop.","properties":{"enabled":{"type":"boolean","description":"Whether networking is enabled for this sandbox.","default":true},"max_connections":{"type":["integer","null"],"description":"Max concurrent guest connections.","default":null,"minimum":0},"policy":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/NetworkPolicy","description":"Egress/ingress policy."}],"default":null},"secrets":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudSecretsConfig","description":"Secret-injection config."}],"default":null}},"additionalProperties":false},"CloudPatch":{"oneOf":[{"type":"object","description":"Write text content to a file.","required":["path","content","replace","type"],"properties":{"content":{"type":"string","description":"Text content to write."},"mode":{"type":["integer","null"],"format":"int32","description":"File permissions, such as `0o644`. `None` uses the default.","minimum":0},"path":{"type":"string","description":"Absolute guest path, such as `/etc/app.conf`."},"replace":{"type":"boolean","description":"Allow replacing a file that already exists in the rootfs."},"type":{"type":"string","enum":["text"]}}},{"type":"object","description":"Write raw bytes to a file.","required":["path","content","replace","type"],"properties":{"content":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Raw byte content to write."},"mode":{"type":["integer","null"],"format":"int32","description":"File permissions, such as `0o644`. `None` uses the default.","minimum":0},"path":{"type":"string","description":"Absolute guest path."},"replace":{"type":"boolean","description":"Allow replacing a file that already exists in the rootfs."},"type":{"type":"string","enum":["file"]}}},{"type":"object","description":"Copy a file from the host into the rootfs.","required":["src","dst","replace","type"],"properties":{"dst":{"type":"string","description":"Absolute guest destination path."},"mode":{"type":["integer","null"],"format":"int32","description":"File permissions. `None` preserves source permissions.","minimum":0},"replace":{"type":"boolean","description":"Allow replacing a file that already exists in the rootfs."},"src":{"type":"string","description":"Host path to copy from."},"type":{"type":"string","enum":["copy_file"]}}},{"type":"object","description":"Copy a directory from the host into the rootfs.","required":["src","dst","replace","type"],"properties":{"dst":{"type":"string","description":"Absolute guest destination path."},"replace":{"type":"boolean","description":"Allow replacing files that already exist in the rootfs."},"src":{"type":"string","description":"Host directory to copy from."},"type":{"type":"string","enum":["copy_dir"]}}},{"type":"object","description":"Create a symlink.","required":["target","link","replace","type"],"properties":{"link":{"type":"string","description":"Absolute guest path where the symlink is created."},"replace":{"type":"boolean","description":"Allow replacing a path that already exists in the rootfs."},"target":{"type":"string","description":"Symlink target path."},"type":{"type":"string","enum":["symlink"]}}},{"type":"object","description":"Create a directory.","required":["path","type"],"properties":{"mode":{"type":["integer","null"],"format":"int32","description":"Directory permissions, such as `0o755`. `None` uses the default.","minimum":0},"path":{"type":"string","description":"Absolute guest path."},"type":{"type":"string","enum":["mkdir"]}}},{"type":"object","description":"Remove a file or directory.","required":["path","type"],"properties":{"path":{"type":"string","description":"Absolute guest path to remove."},"type":{"type":"string","enum":["remove"]}}},{"type":"object","description":"Append content to an existing file.","required":["path","content","type"],"properties":{"content":{"type":"string","description":"Content to append."},"path":{"type":"string","description":"Absolute guest path of the file to append to."},"type":{"type":"string","enum":["append"]}}}],"description":"Rootfs patch applied before VM start. Twin of [`Patch`], internally tagged\nwith a snake_case `type` instead of the domain's external PascalCase tag."},"CloudPullPolicy":{"type":"string","description":"Cloud pull policy. Twin of domain [`PullPolicy`] with a snake_case wire.","enum":["if_missing","always","never"]},"CloudRlimit":{"type":"object","description":"A POSIX resource limit. Twin of [`Rlimit`] using [`CloudRlimitResource`].","required":["resource","soft","hard"],"properties":{"hard":{"type":"integer","format":"int64","description":"Hard limit (ceiling, requires privileges to raise).","minimum":0},"resource":{"$ref":"#/components/schemas/CloudRlimitResource","description":"Resource type."},"soft":{"type":"integer","format":"int64","description":"Soft limit (can be raised up to the hard limit by the process).","minimum":0}}},"CloudRlimitResource":{"type":"string","description":"POSIX resource-limit identifiers. Twin of [`RlimitResource`] with a\nsnake_case wire.","enum":["cpu","fsize","data","stack","core","rss","nproc","nofile","memlock","as","locks","sigpending","msgqueue","nice","rtprio","rttime"]},"CloudSandboxResources":{"type":"object","description":"Cloud resource request.","properties":{"disk_size_mib":{"type":["integer","null"],"format":"int32","description":"Writable disk size in MiB. Applies only to OCI root filesystems.","default":null,"minimum":0},"memory_mib":{"type":"integer","format":"int32","description":"Guest memory in MiB.","default":512,"minimum":0},"vcpus":{"type":"integer","format":"int32","description":"Number of virtual CPUs.","default":1,"minimum":0}}},"CloudSandboxRuntimeOptions":{"type":"object","description":"Cloud guest runtime options: a subset of [`SandboxRuntimeOptions`]. The\nhostname and the metrics-sampling knobs are not part of this type.\n`deny_unknown_fields`.","properties":{"cmd":{"type":["array","null"],"items":{"type":"string"},"description":"Command override.","default":null},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Entrypoint override.","default":null},"log_level":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SandboxLogLevel","description":"Runtime log level."}],"default":null},"scripts":{"type":"object","description":"Named in-guest scripts.","default":{},"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"shell":{"type":["string","null"],"description":"Default shell.","default":null},"user":{"type":["string","null"],"description":"Guest user.","default":null},"workdir":{"type":["string","null"],"description":"Working directory for guest commands.","default":null}},"additionalProperties":false},"CloudSandboxSpec":{"type":"object","description":"Cloud sandbox specification carried on create routes.","properties":{"env":{"type":"array","items":{"$ref":"#/components/schemas/EnvVar"},"description":"Environment variables visible to commands in the sandbox.","default":[]},"image":{"type":"object","description":"Root filesystem source."},"init":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HandoffInit","description":"Hand off PID 1 to a guest init binary after agentd setup."}],"default":null},"labels":{"type":"object","description":"User-defined labels attached to the sandbox.","default":{},"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"lifecycle":{"oneOf":[{"$ref":"#/components/schemas/SandboxPolicy","description":"Sandbox lifecycle policy."}],"default":{"ephemeral":false,"idle_timeout_secs":null,"max_duration_secs":null}},"mounts":{"type":"array","items":{"$ref":"#/components/schemas/CloudVolumeMount"},"description":"Volume mounts.","default":[]},"name":{"type":"string","description":"Unique sandbox name.","default":""},"network":{"oneOf":[{"$ref":"#/components/schemas/CloudNetworkSpec","description":"Network specification."}],"default":{"enabled":true}},"patches":{"type":"array","items":{"$ref":"#/components/schemas/CloudPatch"},"description":"Rootfs patches applied before VM start.","default":[]},"pull_policy":{"oneOf":[{"$ref":"#/components/schemas/CloudPullPolicy","description":"Pull policy for OCI images."}],"default":"if_missing"},"resources":{"oneOf":[{"$ref":"#/components/schemas/CloudSandboxResources","description":"CPU, memory, and user-facing disk resources."}],"default":{"memory_mib":512,"vcpus":1}},"rlimits":{"type":"array","items":{"$ref":"#/components/schemas/CloudRlimit"},"description":"Sandbox-wide resource limits inherited by guest processes.","default":[]},"runtime":{"oneOf":[{"$ref":"#/components/schemas/CloudSandboxRuntimeOptions","description":"Guest runtime options."}],"default":{"cmd":null,"entrypoint":null,"log_level":null,"scripts":{},"shell":null,"user":null,"workdir":null}},"security_profile":{"oneOf":[{"$ref":"#/components/schemas/SecurityProfile","description":"In-guest security profile."}],"default":"default"}}},"CloudSecretEntry":{"type":"object","description":"A single cloud secret entry. Twin of domain [`SecretEntry`].","required":["env_var","placeholder"],"properties":{"allowed_hosts":{"type":"array","items":{"$ref":"#/components/schemas/CloudHostPattern"},"description":"Hosts allowed to receive this secret."},"env_var":{"type":"string","description":"Environment variable name exposed to the sandbox."},"injection":{"$ref":"#/components/schemas/SecretInjection","description":"Where the secret may be injected."},"on_violation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudViolationAction","description":"Per-secret violation action overriding the config default."}]},"placeholder":{"type":"string","description":"Placeholder the sandbox sees instead of the real value."},"require_tls_identity":{"type":"boolean","description":"Require verified TLS identity before substituting (default: true)."},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudSecretSource","description":"Host-side source resolved into `value` at spawn time."}]},"value":{"type":"string","description":"The secret value (empty when `source` carries a reference instead)."}}},"CloudSecretSource":{"oneOf":[{"type":"object","description":"Read from a host environment variable at apply time.","required":["var","type"],"properties":{"type":{"type":"string","enum":["env"]},"var":{"type":"string","description":"Host environment variable name."}}},{"type":"object","description":"Read from a host-side secret store reference.","required":["reference","type"],"properties":{"reference":{"type":"string","description":"Store-specific secret reference."},"type":{"type":"string","enum":["store"]}}}],"description":"Host-side source for a cloud secret. Twin of [`SecretSource`]."},"CloudSecretsConfig":{"type":"object","description":"Secret-injection config for the cloud API. Twin of domain [`SecretsConfig`].","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/CloudSecretEntry"},"description":"Secrets to inject."},"on_violation":{"$ref":"#/components/schemas/CloudViolationAction","description":"Default action when a placeholder leaks to a disallowed host."}}},"CloudViolationAction":{"oneOf":[{"type":"object","description":"Block the request silently.","required":["type"],"properties":{"type":{"type":"string","enum":["block"]}}},{"type":"object","description":"Block and log (default).","required":["type"],"properties":{"type":{"type":"string","enum":["block_and_log"]}}},{"type":"object","description":"Block and terminate the sandbox.","required":["type"],"properties":{"type":{"type":"string","enum":["block_and_terminate"]}}},{"type":"object","description":"Forward the request with the placeholder unchanged for matching hosts.","required":["hosts","type"],"properties":{"hosts":{"type":"array","items":{"$ref":"#/components/schemas/CloudHostPattern"},"description":"Hosts for which the placeholder passes through unchanged."},"type":{"type":"string","enum":["passthrough"]}}}],"description":"Action on a cloud secret violation. Twin of [`ViolationAction`], with\n`Passthrough`'s host list normalized to a `hosts` field."},"CloudVolumeMount":{"oneOf":[{"type":"object","description":"Bind mount a host directory into the guest.","required":["host","guest","type"],"properties":{"guest":{"type":"string","description":"Guest path to mount at."},"host":{"type":"string","description":"Host directory to bind into the guest."},"host_permissions":{"$ref":"#/components/schemas/HostPermissions","description":"Host permission policy applied to the mount."},"options":{"$ref":"#/components/schemas/MountOptions","description":"Mount options (read-only, no-exec, …)."},"quota_mib":{"type":["integer","null"],"format":"int32","description":"Optional guest-write quota in MiB.","minimum":0},"stat_virtualization":{"$ref":"#/components/schemas/StatVirtualization","description":"How guest `stat()` results are virtualized."},"type":{"type":"string","enum":["bind"]}}},{"type":"object","description":"Mount a named volume into the guest.","required":["name","guest","type"],"properties":{"guest":{"type":"string","description":"Guest path to mount at."},"host_permissions":{"$ref":"#/components/schemas/HostPermissions","description":"Host permission policy applied to the mount."},"name":{"type":"string","description":"Named volume to mount."},"options":{"$ref":"#/components/schemas/MountOptions","description":"Mount options (read-only, no-exec, …)."},"stat_virtualization":{"$ref":"#/components/schemas/StatVirtualization","description":"How guest `stat()` results are virtualized."},"type":{"type":"string","enum":["named"]}}},{"type":"object","description":"Temporary filesystem backed by guest memory.","required":["guest","type"],"properties":{"guest":{"type":"string","description":"Guest path to mount at."},"options":{"$ref":"#/components/schemas/MountOptions","description":"Mount options (read-only, no-exec, …)."},"size_mib":{"type":["integer","null"],"format":"int32","description":"Optional size cap in MiB.","minimum":0},"type":{"type":"string","enum":["tmpfs"]}}},{"type":"object","description":"Mount a disk image file as a virtio-blk device at a guest path.","required":["host","guest","format","type"],"properties":{"format":{"$ref":"#/components/schemas/CloudDiskImageFormat","description":"Disk image format."},"fstype":{"type":["string","null"],"description":"Inner filesystem type (auto-detected if absent)."},"guest":{"type":"string","description":"Guest path to mount at."},"host":{"type":"string","description":"Host path to the disk image file."},"options":{"$ref":"#/components/schemas/MountOptions","description":"Mount options (read-only, no-exec, …)."},"type":{"type":"string","enum":["disk_image"]}}}],"description":"Cloud volume mount. Internal-tagged mirror of the domain [`VolumeMount`];\nthe transient `create` field is not carried on the wire."},"ComponentStatus":{"type":"object","description":"Status of an individual component.","required":["status"],"properties":{"error":{"type":["string","null"]},"status":{"type":"string"}}},"CreateApiKeyRequest":{"type":"object","description":"POST /v1/orgs/:slug/api-keys","required":["name"],"properties":{"name":{"type":"string"}}},"CreateApiKeyResponse":{"type":"object","description":"Returned to the caller once on creation — includes the full plaintext key.","required":["id","name","key","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"key":{"type":"string"},"name":{"type":"string"}}},"CreateInviteRequest":{"type":"object","description":"Request body for `POST /v1/orgs/:slug/invites`.","required":["email","role"],"properties":{"email":{"type":"string"},"role":{"$ref":"#/components/schemas/OrgRole"}}},"CreateOrgRequest":{"type":"object","description":"POST /v1/orgs — create a new organization.","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"CreatePersonalAccessTokenRequest":{"type":"object","description":"POST /v1/users/me/pats","required":["name"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","description":"Optional ISO-8601 expiry. Omitted = no expiry."},"name":{"type":"string","description":"Human-readable label for the token (e.g. \"macbook-cli\")."}}},"CreatePersonalAccessTokenResponse":{"type":"object","description":"Returned to the caller once on creation — includes the full plaintext token.","required":["id","name","prefix","token","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string"},"token":{"type":"string","description":"Raw bearer token in the form `msb_pat_<env>_<random>`. Surfaced once."}}},"CreateSandboxRequest":{"allOf":[{"$ref":"#/components/schemas/CloudCreateSandboxRequest","description":"The microsandbox sandbox specification — image, resources, runtime, env,\nmounts, network, lifecycle — flattened onto the request body."},{"type":"object","properties":{"registry":{"$ref":"#/components/schemas/RegistrySelection","description":"Registry-credential selection for the image pull. Absent ⇒ `Auto`\n(infer the credential from the image's registry host). Credential-only:\nthis never changes *where* the image is pulled from — the image string\ncontrols that — only *which* stored credential, if any, is presented."},"slug":{"type":["string","null"],"description":"Optional globally-unique slug — the SSH username token. Lowercase\nletters, digits, and single hyphens; 3–63 chars. Omitted ⇒ a dictionary\nslug is generated. Must be globally unique (409 on conflict)."}}}],"description":"What the user sends in `POST /v1/sandboxes`.\n\nThe body *is* a microsandbox [`CloudSandboxSpec`] — carried verbatim through the\nshared [`CloudCreateSandboxRequest`] envelope (flattened onto the wire) so it\ncan never drift from the cross-repo contract — plus the cloud-only fields\nthat have no place in the shared spec: the globally-unique SSH `slug` and the\nregistry-credential selection. (Writable-disk size now lives in the spec's\n`resources.disk_size_mib`.)"},"CreateVolumeRequest":{"type":"object","description":"POST /v1/orgs/{slug}/volumes","required":["name"],"properties":{"capacity_gib":{"type":["integer","null"],"format":"int32","description":"Optional per-volume storage cap in GiB (#496). Omitted/`null` = no\nper-volume limit (the org's plan cap still governs). Must be `>= 1` and\n`<= the org's storage cap`.","minimum":0},"labels":{"type":"object","description":"User-defined labels (free-form string map). Omitted = none. Keys using a\nplatform-reserved prefix are rejected.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Volume name, unique within the org. Lowercase alphanumeric with single\ninternal hyphens (e.g. `team-ml`). Creates a `managed` volume; the host\ndisk is system-provisioned and has no name."},"storage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/VolumeType","description":"Physical backing for the volume. Omitted = `block` (the default and only\nvalue today)."}]}}},"DeleteMeRequest":{"type":"object","description":"DELETE /v1/users/me — body confirms the destructive action.\n\nProvide exactly one credential proof: the current password (for\npassword-backed accounts) or a TOTP code (when MFA is enabled).\nOAuth-only accounts must enrol in MFA before deletion is permitted.","properties":{"mfa_code":{"type":["string","null"],"description":"TOTP code — required when MFA is enabled."},"password":{"type":["string","null"],"description":"Current account password — required for password-backed accounts."}}},"DeleteOrgRequest":{"type":"object","description":"DELETE /v1/orgs/:slug — delete an organization. `confirm` must echo the org slug,\nmirroring the dashboard's type-to-confirm, so a deletion can't fire by accident.","required":["confirm"],"properties":{"confirm":{"type":"string"}}},"Destination":{"oneOf":[{"type":"string","description":"Match any destination.","enum":["any"]},{"type":"object","description":"IP address or CIDR block (e.g. `\"1.2.3.4\"`, `\"10.0.0.0/8\"`).","required":["cidr"],"properties":{"cidr":{"type":"string","description":"IP address or CIDR block (e.g. `\"1.2.3.4\"`, `\"10.0.0.0/8\"`)."}}},{"type":"object","description":"Exact domain name (e.g. `\"example.com\"`).","required":["domain"],"properties":{"domain":{"type":"string","description":"Exact domain name (e.g. `\"example.com\"`)."}}},{"type":"object","description":"Domain suffix — the apex and any subdomain of it.","required":["domain_suffix"],"properties":{"domain_suffix":{"type":"string","description":"Domain suffix — the apex and any subdomain of it."}}},{"type":"object","description":"A pre-defined destination group.","required":["group"],"properties":{"group":{"$ref":"#/components/schemas/DestinationGroup","description":"A pre-defined destination group."}}}],"description":"Traffic destination filter for a [`Rule`].\n\nThe `Cidr`, `Domain`, and `DomainSuffix` leaves carry their canonical\nstring form (e.g. `\"10.0.0.0/8\"`, `\"example.com\"`); the local network\nengine re-parses and validates them into its richer internal types at\nload time."},"DestinationGroup":{"type":"string","description":"Pre-defined destination category for a [`Destination::Group`] match.","enum":["public","loopback","private","link_local","metadata","multicast","host"]},"Direction":{"type":"string","description":"Direction a [`Rule`] applies to.","enum":["egress","ingress","any"]},"DiskImageFormat":{"type":"string","description":"Disk image format for virtio-blk root filesystems and volume mounts.","enum":["Qcow2","Raw","Vmdk"]},"DnsConfig":{"type":"object","description":"DNS interception and filtering settings. Carried in [`NetworkSpec::dns`].","properties":{"nameservers":{"type":"array","items":{"type":"string"},"description":"Upstream nameservers as `IP`, `IP:PORT`, `HOST`, or `HOST:PORT`\nstrings. Empty falls back to the host's `/etc/resolv.conf`.","default":[]},"query_timeout_ms":{"type":"integer","format":"int64","description":"Per-query timeout in milliseconds. Default: 5000.","default":5000,"minimum":0},"rebind_protection":{"type":"boolean","description":"Whether DNS-rebinding protection is enabled. Default: true.","default":true}}},"EnvVar":{"type":"object","description":"Environment variable entry.","required":["key","value"],"properties":{"key":{"type":"string","description":"Environment variable name."},"value":{"type":"string","description":"Environment variable value."}}},"EventActor":{"oneOf":[{"type":"object","required":["user_id","label","redacted_email","kind"],"properties":{"kind":{"type":"string","enum":["user"]},"label":{"type":"string"},"redacted_email":{"type":"string"},"user_id":{"type":"string","format":"uuid"}}},{"type":"object","required":["api_key_id","name","kind"],"properties":{"api_key_id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["api_key"]},"name":{"type":"string"}}},{"type":"object","required":["code","label","kind"],"properties":{"code":{"type":"string"},"kind":{"type":"string","enum":["system"]},"label":{"type":"string"}}},{"type":"object","description":"The authorized SSH key that authenticated a front-door session. The\nprincipal SSH actually proves at connect is the *key*, not a person —\nthe scope-only model (D8) doesn't bind a key to a user (a global key may\nbe shared), so the session is attributed to the key (label + fingerprint),\nwhile whoever registered it rides the event payload as `added_by`.","required":["key_id","fingerprint","kind"],"properties":{"fingerprint":{"type":"string","description":"`SHA256:…` fingerprint."},"key_id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["ssh_key"]},"label":{"type":["string","null"],"description":"Human label set at registration (e.g. `alice-laptop`), if any."}}}],"description":"Maximum total length, in characters, of the truncated `command` field in\nImmutable actor snapshot stored alongside an event."},"EventResponse":{"type":"object","description":"A single audit/lifecycle event returned by the API.","required":["id","org_id","category","event_type","actor","payload","timestamp"],"properties":{"actor":{"$ref":"#/components/schemas/EventActor"},"category":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"payload":{},"timestamp":{"type":"string","format":"date-time"}}},"FileMoveRequest":{"type":"object","required":["from","to"],"properties":{"from":{"type":"string"},"to":{"type":"string"}}},"FilePathRequest":{"type":"object","required":["path"],"properties":{"path":{"type":"string"}}},"ForgotPasswordRequest":{"type":"object","description":"POST /v1/auth/forgot-password","required":["email"],"properties":{"email":{"type":"string"}}},"GrantAccountCreditRequest":{"type":"object","description":"Request body for granting an organization future Stripe invoice credit.","required":["org_id","amount_cents","operator_message","issued_by","reference"],"properties":{"amount_cents":{"type":"integer","format":"int32","description":"Positive USD amount in cents.","minimum":0},"issued_by":{"type":"string"},"operator_message":{"type":"string"},"org_id":{"type":"string","format":"uuid"},"reference":{"type":"string","description":"Stable support/ticket reference used to make retries idempotent."}}},"HandoffInit":{"type":"object","description":"Fully-assembled handoff-init specification.","required":["cmd"],"properties":{"args":{"type":"array","items":{"type":"string"},"description":"Supplemental argv. `argv[0]` is implicitly `cmd`."},"cmd":{"type":"string","description":"Init binary: absolute path inside the guest rootfs, or the literal `auto`.\n\nAlways a Linux-style `/`-separated path — never build it with host OS path APIs, whose semantics diverge on Windows (`\\` separators, `/sbin/init` treated as relative)."},"env":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"Extra env vars merged on top of the inherited env."}}},"HealthResponse":{"type":"object","description":"Health check response.","required":["status"],"properties":{"status":{"type":"string"}}},"HostPermissions":{"type":"string","description":"Host permission propagation policy for a virtiofs-backed volume mount.\n\nSerializes/deserializes as the lowercase variant name (`\"private\"`, `\"mirror\"`) to align with the CLI and NAPI spellings.","enum":["private","mirror"]},"InterceptCaConfig":{"type":"object","description":"Certificate authority configuration for TLS interception.","properties":{"cert_path":{"type":["string","null"],"description":"Path to an existing CA certificate PEM file. If `None`, a CA is\nauto-generated and persisted."},"key_path":{"type":["string","null"],"description":"Path to an existing CA private key PEM file. If `None`, a key is\nauto-generated and persisted."}}},"InterfaceOverrides":{"type":"object","description":"Optional guest interface overrides. Unset fields are derived from the\nsandbox slot by the local network engine. Carried in\n[`NetworkSpec::interface`].","properties":{"ipv4_address":{"type":["string","null"],"description":"Guest IPv4 address (e.g. `172.16.0.2`). Default: derived from slot.","default":null},"ipv4_pool":{"type":["string","null"],"description":"Guest IPv4 pool CIDR (e.g. `\"172.16.0.0/12\"`). Default: derived from slot.","default":null},"ipv6_address":{"type":["string","null"],"description":"Guest IPv6 address. Default: derived from slot.","default":null},"ipv6_pool":{"type":["string","null"],"description":"Guest IPv6 pool CIDR. Default: derived from slot.","default":null},"mac":{"type":["array","null"],"items":{"type":"integer","format":"int32","minimum":0},"description":"Guest MAC address as six octets. Default: derived from slot.","default":null},"mtu":{"type":["integer","null"],"format":"int32","description":"Interface MTU. Default: 1500.","default":null,"minimum":0}}},"Invoice":{"type":"object","description":"Invoice from the billing provider (Autumn/Stripe).","required":["id","status","total_cents","currency","period_start","period_end","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"currency":{"type":"string"},"id":{"type":"string"},"invoice_url":{"type":["string","null"]},"period_end":{"type":"string","format":"date-time"},"period_start":{"type":"string","format":"date-time"},"status":{"type":"string"},"total_cents":{"type":"integer","format":"int64"}}},"JoinWaitlistRequest":{"type":"object","description":"Request-access body for the public waitlist endpoint.","required":["email"],"properties":{"email":{"type":"string"}}},"LoginRequest":{"type":"object","description":"POST /v1/auth/login","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LoginResponse":{"oneOf":[{"type":"object","required":["access_token","refresh_token","expires_in","status"],"properties":{"access_token":{"type":"string"},"expires_in":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"},"status":{"type":"string","enum":["authenticated"]}}},{"type":"object","required":["challenge_token","methods","status"],"properties":{"challenge_token":{"type":"string"},"methods":{"type":"array","items":{"$ref":"#/components/schemas/MfaMethod"}},"status":{"type":"string","enum":["two_factor_required"]}}}],"description":"Successful authentication or a pending TOTP challenge."},"LoginTwoFactorRequest":{"type":"object","description":"POST /v1/auth/login/2fa","required":["challenge_token"],"properties":{"challenge_token":{"type":"string"},"code":{"type":["string","null"]},"recovery_code":{"type":["string","null"]}}},"MessageResponse":{"type":"object","description":"Simple message response for operations without a body.","required":["message"],"properties":{"message":{"type":"string"}}},"MetricSeries":{"type":"object","description":"One labelled series for a metric.","required":["labels","samples"],"properties":{"labels":{"type":"object","description":"Series labels (e.g. `sandbox_name`), minus internal Prometheus names.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"samples":{"type":"array","items":{"type":"array","items":{"type":"number","format":"double"}},"description":"`[epoch_millis, value]` pairs in ascending time order."}}},"MetricsRange":{"type":"object","description":"The resolved time window a metrics response covers.","required":["start","end","step_secs"],"properties":{"end":{"type":"integer","format":"int64","description":"Window end, epoch milliseconds."},"start":{"type":"integer","format":"int64","description":"Window start, epoch milliseconds."},"step_secs":{"type":"integer","format":"int64","description":"Sample resolution in seconds.","minimum":0}}},"MfaConfirmRequest":{"type":"object","description":"Request body for confirming MFA setup with a TOTP code.","required":["code"],"properties":{"code":{"type":"string"}}},"MfaMethod":{"type":"string","description":"Supported second-factor methods for a pending login challenge.","enum":["totp","recovery_code"]},"MfaRecoveryCode":{"type":"object","description":"A single-use recovery code for a user's MFA enrollment.","required":["id","user_id","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"used_at":{"type":["string","null"],"format":"date-time"},"user_id":{"type":"string","format":"uuid"}}},"MfaSetupResponse":{"type":"object","description":"Response from initiating MFA setup — contains the secret and provisioning URI.","required":["secret","provisioning_uri","issuer","account_name"],"properties":{"account_name":{"type":"string"},"issuer":{"type":"string"},"provisioning_uri":{"type":"string"},"secret":{"type":"string"}}},"MfaStatusResponse":{"type":"object","description":"MFA enrollment status for the current user.","required":["mfa_enabled","recovery_codes_remaining"],"properties":{"mfa_enabled":{"type":"boolean"},"recovery_codes_remaining":{"type":"integer","format":"int64"}}},"MountOptions":{"type":"object","description":"Guest mount behavior shared by every volume mount kind.","properties":{"nodev":{"type":"boolean","description":"Whether device files on the mount are ignored.","default":false},"noexec":{"type":"boolean","description":"Whether direct execution from the mount is disabled.\n\nThis prevents `execve` of binaries or scripts located on the mount. Interpreters can still read files from the mount, for example `sh /mnt/script.sh`, because the interpreter itself executes from a different filesystem.","default":false},"nosuid":{"type":"boolean","description":"Whether setuid and setgid privilege elevation from files on the mount is ignored.","default":false},"readonly":{"type":"boolean","description":"Whether the mount is read-only.\n\nGuest writes fail with the kernel's read-only filesystem behavior. Virtiofs-backed mounts also reject writes on the host-side filesystem server as defense in depth.","default":false}}},"NetworkPolicy":{"type":"object","description":"Egress/ingress network policy: an ordered [`Rule`] list plus a\nper-direction default [`Action`]. Carried in [`NetworkSpec::policy`].","properties":{"default_egress":{"$ref":"#/components/schemas/Action","description":"Default action for egress traffic matching no rule. Default: `Deny`."},"default_ingress":{"$ref":"#/components/schemas/Action","description":"Default action for ingress traffic matching no rule. Default: `Deny`."},"rules":{"type":"array","items":{"$ref":"#/components/schemas/Rule"},"description":"Ordered rules, evaluated first-match-wins per direction."}}},"OAuthCallbackQuery":{"type":"object","description":"Query params for GET /v1/auth/oauth/{provider}/callback","required":["code","state"],"properties":{"code":{"type":"string"},"state":{"type":"string"}}},"OAuthInitiateResponse":{"type":"object","description":"Response for GET /v1/auth/oauth/{provider} — authorization URL to redirect the user to.","required":["authorize_url"],"properties":{"authorize_url":{"type":"string"}}},"OidcCallbackQuery":{"type":"object","description":"Query parameters from the OIDC provider callback redirect.","required":["code","state"],"properties":{"code":{"type":"string"},"state":{"type":"string"}}},"OidcInitiateResponse":{"type":"object","description":"Response for GET /v1/auth/oidc/{org_slug} (initiate OIDC flow).","required":["authorize_url"],"properties":{"authorize_url":{"type":"string"}}},"OrgBillingTermsOverrideStatus":{"type":"string","description":"Operational state of one immutable negotiated-pricing version.","enum":["applying","pending_payment","scheduled","active","failed","expired"]},"OrgInvite":{"type":"object","description":"An email-based invitation to join an organization.","required":["id","org_id","email","role","invited_by","expires_at","created_at"],"properties":{"accepted_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"declined_at":{"type":["string","null"],"format":"date-time"},"email":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"invited_by":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"role":{"$ref":"#/components/schemas/OrgRole"}}},"OrgMember":{"type":"object","description":"A user's membership in an organization.","required":["id","org_id","user_id","role","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"role":{"$ref":"#/components/schemas/OrgRole"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":"string","format":"uuid"}}},"OrgMemberResponse":{"type":"object","description":"Member with joined user profile data — repository read view.","required":["id","user_id","email","role","joined_at"],"properties":{"avatar_url":{"type":["string","null"]},"display_name":{"type":["string","null"]},"email":{"type":"string"},"id":{"type":"string","format":"uuid"},"joined_at":{"type":"string","format":"date-time"},"role":{"$ref":"#/components/schemas/OrgRole"},"user_id":{"type":"string","format":"uuid"}}},"OrgOidcConfig":{"type":"object","description":"OIDC configuration for an organization's enterprise SSO.","required":["id","org_id","issuer_url","client_id","allowed_domains","enabled","created_at","updated_at"],"properties":{"allowed_domains":{"type":"array","items":{"type":"string"}},"client_id":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"enabled":{"type":"boolean"},"id":{"type":"string","format":"uuid"},"issuer_url":{"type":"string"},"org_id":{"type":"string","format":"uuid"},"updated_at":{"type":"string","format":"date-time"}}},"OrgRole":{"type":"string","description":"Organization membership role.","enum":["owner","admin","member","viewer"]},"OrgWithRole":{"type":"object","description":"Organization with the requesting user's role included.","required":["id","name","slug","mfa_required","role","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"mfa_required":{"type":"boolean"},"name":{"type":"string"},"role":{"$ref":"#/components/schemas/OrgRole"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"Organization":{"type":"object","description":"A tenant organization. Users belong to orgs via `OrgMember`.","required":["id","name","slug","mfa_required","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"mfa_required":{"type":"boolean"},"name":{"type":"string"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"PaginatedApiKeyResponse":{"type":"object","description":"Paginated list of API keys (OpenAPI schema for `PaginatedResponse<ApiKeyResponse>`).","required":["data","has_more"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"PaginatedEventResponse":{"type":"object","description":"Wrapper for paginated event responses (needed for OpenAPI schema generation).","required":["data","has_more"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EventResponse"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"PaginatedResponse":{"type":"object","description":"Generic paginated response.","required":["data","has_more"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrgMemberResponse"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"PaymentPortalResponse":{"type":"object","description":"Response for the payment-portal endpoint — a hosted URL the client redirects\nto for adding/managing payment methods (Stripe Checkout / billing-portal).","required":["portal_url"],"properties":{"portal_url":{"type":"string"}}},"PersonalAccessTokenResponse":{"type":"object","description":"PAT metadata returned in list responses. Never includes the raw token.","required":["id","name","prefix","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"id":{"type":"string","format":"uuid"},"last_used_at":{"type":["string","null"],"format":"date-time"},"name":{"type":"string"},"prefix":{"type":"string","description":"Last 8 chars of the original token — safe to display."}}},"PoolUsage":{"type":"object","description":"An org's monthly pool usage against its hard-cap pools — the shared home of\nthe exhaustion predicates, whether read per-org (embedded in `QuotaUsage`)\nor in the quota monitor's batched sweep (`OrgPoolUsage`).","required":["hard_cap","vcpu_hours_used","memory_gib_hours_used"],"properties":{"hard_cap":{"type":"boolean","description":"Whether the plan hard-stops at its included pools (no overflow).\nDERIVED (not a stored column): true iff the resolved plan is unpriced —\nan unpriced plan has no overage path, so its pools become walls."},"included_memory_gib_hours":{"type":["integer","null"],"format":"int32","description":"Included memory GiB-hours/month; `None` = unlimited."},"included_vcpu_hours":{"type":["integer","null"],"format":"int32","description":"Included vCPU-hours/month; `None` = unlimited. On `hard_cap` plans this\nis the compute wall; on priced plans, usage beyond it is metered overage."},"memory_gib_hours_used":{"type":"number","format":"double","description":"Memory GiB-hours consumed this billing month (compute-on-read from `sandbox_runs`)."},"vcpu_hours_used":{"type":"number","format":"double","description":"vCPU-hours consumed this billing month (compute-on-read from `sandbox_runs`)."}}},"PortProtocol":{"type":"string","description":"Transport protocol for a published port.","enum":["tcp","udp"]},"PortRange":{"type":"object","description":"Inclusive guest-side port range for a [`Rule`] match.","required":["start","end"],"properties":{"end":{"type":"integer","format":"int32","description":"End port (inclusive).","minimum":0},"start":{"type":"integer","format":"int32","description":"Start port (inclusive).","minimum":0}}},"Protocol":{"type":"string","description":"Protocol filter for a [`Rule`].","enum":["tcp","udp","icmpv4","icmpv6"]},"PublishedPortSpec":{"type":"object","description":"A published port mapping between host and guest.","required":["host_port","guest_port","host_bind"],"properties":{"guest_port":{"type":"integer","format":"int32","description":"Guest-side port to forward to.","minimum":0},"host_bind":{"type":"string","description":"Host address to bind. Defaults to loopback."},"host_port":{"type":"integer","format":"int32","description":"Host-side port to bind.","minimum":0},"protocol":{"$ref":"#/components/schemas/PortProtocol","description":"Transport protocol."}}},"QuotaOverride":{"type":"object","description":"Per-org quota override values (nullable — only set fields override).","required":["org_id"],"properties":{"max_concurrent_ephemeral_running":{"type":["integer","null"],"format":"int32"},"max_concurrent_persistent_running":{"type":["integer","null"],"format":"int32"},"max_disk_size_mib_per_sandbox":{"type":["integer","null"],"format":"int32"},"max_memory_mib_per_sandbox":{"type":["integer","null"],"format":"int32"},"max_sandboxes":{"type":["integer","null"],"format":"int32"},"max_total_storage_gib":{"type":["integer","null"],"format":"int32"},"max_uptime_minutes_per_sandbox":{"type":["integer","null"],"format":"int32"},"max_vcpus_per_sandbox":{"type":["integer","null"],"format":"int32"},"org_id":{"type":"string","format":"uuid"}}},"QuotaUsage":{"allOf":[{"$ref":"#/components/schemas/PoolUsage"},{"type":"object","required":["pool_exhausted","total_sandboxes","concurrent_ephemeral_running","concurrent_persistent_running","is_suspended"],"properties":{"concurrent_ephemeral_running":{"type":"integer","format":"int64","description":"Currently running/starting ephemeral sandboxes."},"concurrent_persistent_running":{"type":"integer","format":"int64","description":"Currently running/starting persistent sandboxes."},"included_disk_gib_hours":{"type":["integer","null"],"format":"int32","description":"Included writable-disk GiB-hours/month (display/billing only — never a wall)."},"included_storage_gib":{"type":["integer","null"],"format":"int32","description":"Included durable-storage GiB/month."},"is_suspended":{"type":"boolean","description":"Whether sandbox usage has been manually suspended for the organization."},"max_concurrent_ephemeral_running":{"type":["integer","null"],"format":"int32","description":"Maximum simultaneously-running ephemeral sandboxes."},"max_concurrent_persistent_running":{"type":["integer","null"],"format":"int32","description":"Maximum simultaneously-running persistent sandboxes."},"max_disk_size_mib_per_sandbox":{"type":["integer","null"],"format":"int32","description":"Maximum writable disk size (MiB) per sandbox."},"max_memory_mib_per_sandbox":{"type":["integer","null"],"format":"int32","description":"Maximum memory (MiB) per sandbox."},"max_sandboxes":{"type":["integer","null"],"format":"int32","description":"Maximum total sandboxes the org can have."},"max_total_storage_gib":{"type":["integer","null"],"format":"int32","description":"Per-org durable-storage hard cap (GiB)."},"max_uptime_minutes_per_sandbox":{"type":["integer","null"],"format":"int32","description":"Maximum uptime per sandbox (minutes), if set."},"max_vcpus_per_sandbox":{"type":["integer","null"],"format":"int32","description":"Maximum CPU cores per sandbox."},"pool_exhausted":{"type":"boolean","description":"Snapshot of [`PoolUsage::pool_exhausted`] at read time, for API\nconsumers — true when this org's sandboxes are being stopped and starts\nrefused."},"total_sandboxes":{"type":"integer","format":"int64","description":"Total sandboxes (all states) for the org."}}}],"description":"Resolved quota limits and current usage for an organization.\n\nLimits are resolved via COALESCE: per-org override > plan. Every limit is\n`Option`: `None` = unlimited (counts/budgets) or the system/node max\n(per-sandbox vcpu/memory/disk). There is no magic 0."},"ReadyzResponse":{"type":"object","description":"Readiness check response with per-component status.","required":["status","database"],"properties":{"database":{"$ref":"#/components/schemas/ComponentStatus"},"status":{"type":"string"}}},"RecoveryCodesResponse":{"type":"object","description":"Response containing a fresh set of recovery codes.","required":["recovery_codes"],"properties":{"recovery_codes":{"type":"array","items":{"type":"string"}}}},"RefreshRequest":{"type":"object","description":"POST /v1/auth/refresh","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"RegisterRequest":{"type":"object","description":"POST /v1/auth/register","required":["email","password"],"properties":{"display_name":{"type":["string","null"]},"email":{"type":"string"},"password":{"type":"string"}}},"RegistryCredentialResponse":{"type":"object","description":"Registry credential metadata returned in list/upsert responses. Never includes\nthe secret or the internal vault path.","required":["id","registry_host","username","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"registry_host":{"type":"string"},"updated_at":{"type":"string","format":"date-time"},"username":{"type":"string"}}},"RegistrySelection":{"oneOf":[{"type":"object","description":"Infer a stored credential from the image registry host.","required":["mode"],"properties":{"mode":{"type":"string","enum":["auto"]}}},{"type":"object","description":"Force an anonymous pull.","required":["mode"],"properties":{"mode":{"type":"string","enum":["anonymous"]}}},{"type":"object","description":"Use an already-stored organization credential.","required":["credential_id","mode"],"properties":{"credential_id":{"type":"string","format":"uuid","description":"Id of a configured `OrgRegistryCredential` belonging to the org."},"mode":{"type":"string","enum":["specific"]}}},{"type":"object","description":"Use plaintext credentials for this create-and-start operation only.","required":["username","password","mode"],"properties":{"mode":{"type":"string","enum":["inline"]},"password":{"type":"string","format":"password","description":"Registry password or access token. Always redacted from `Debug`."},"username":{"type":"string","description":"Registry username."}}}],"description":"Registry credential selection accepted on sandbox-create requests.\n\n`Inline` is deliberately request-only: its plaintext fields must be vaulted\nbefore persistence and must never enter the sandbox row, a worker launch\ndefinition, a log, or an API response."},"ResetPasswordRequest":{"type":"object","description":"POST /v1/auth/reset-password","required":["token","new_password"],"properties":{"new_password":{"type":"string"},"token":{"type":"string"}}},"Rlimit":{"type":"object","description":"A POSIX resource limit.","required":["resource","soft","hard"],"properties":{"hard":{"type":"integer","format":"int64","description":"Hard limit (ceiling, requires privileges to raise).","minimum":0},"resource":{"$ref":"#/components/schemas/RlimitResource","description":"Resource type."},"soft":{"type":"integer","format":"int64","description":"Soft limit (can be raised up to hard limit by the process).","minimum":0}}},"RlimitResource":{"type":"string","description":"POSIX resource limit identifiers.","enum":["Cpu","Fsize","Data","Stack","Core","Rss","Nproc","Nofile","Memlock","As","Locks","Sigpending","Msgqueue","Nice","Rtprio","Rttime"]},"RotateRecoveryCodesRequest":{"type":"object","description":"Request body for rotating recovery codes (requires a valid TOTP code or recovery code).","properties":{"code":{"type":["string","null"]},"recovery_code":{"type":["string","null"]}}},"Rule":{"type":"object","description":"A single egress/ingress policy rule. Evaluated first-match-wins per\ndirection.","required":["direction","destination","action"],"properties":{"action":{"$ref":"#/components/schemas/Action","description":"Action to take on a match."},"destination":{"$ref":"#/components/schemas/Destination","description":"Destination filter (direction-dependent interpretation)."},"direction":{"$ref":"#/components/schemas/Direction","description":"Direction this rule applies to."},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortRange"},"description":"Guest-side port-range set; empty matches any port."},"protocols":{"type":"array","items":{"$ref":"#/components/schemas/Protocol"},"description":"Protocol set; empty matches any protocol."}}},"SandboxDailyUsage":{"type":"object","description":"Compute usage for one sandbox on one UTC day, across both billed dimensions.\n\nComputed on read from `sandbox_runs` (not from the billing provider) — open runs accrue\nagainst `now()`, so a *running* sandbox shows live usage. Quantities are\nseconds-based (vCPU-seconds, MiB-seconds), the same units the metering events\ncarry; display converts to vCPU-hours / GiB-hours. Sum over days for a\nsandbox's period total; sum over sandboxes for the daily series.","required":["sandbox_id","day","vcpu_seconds","mem_mib_seconds","disk_mib_seconds"],"properties":{"day":{"type":"string","format":"date-time","description":"UTC midnight of the day this usage falls in."},"disk_mib_seconds":{"type":"number","format":"double","description":"Σ(overlap_secs × disk_mib) for this sandbox on this day — provisioned\nwritable disk billed on the same GiB-seconds basis while the sandbox runs."},"mem_mib_seconds":{"type":"number","format":"double","description":"Σ(overlap_secs × mem_mib) for this sandbox on this day."},"sandbox_id":{"type":"string","format":"uuid"},"vcpu_seconds":{"type":"number","format":"double","description":"Σ(overlap_secs × vcpus) for this sandbox on this day."}}},"SandboxIdentity":{"type":"object","description":"Minimal sandbox display info — the directory that turns the `sandbox_id`s in\na [`UsageBreakdown`]'s rows into human labels without a second round-trip.","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"}}},"SandboxLogLevel":{"type":"string","description":"Runtime log verbosity for sandbox specs.","enum":["error","warn","info","debug","trace"]},"SandboxMetricsResponse":{"type":"object","description":"Per-sandbox metrics over a time range, keyed by metric (`cpu`,\n`memory_bytes`, `net_rx_bytes_rate`, …). See `plans/monitoring-plan.md`\n§ B for the catalog.","required":["sandbox_id","range","metrics"],"properties":{"metrics":{"type":"object","description":"Metric key → series. An empty series means \"no data in range\".","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/MetricSeries"}},"propertyNames":{"type":"string"}},"range":{"$ref":"#/components/schemas/MetricsRange","description":"The resolved query window."},"sandbox_id":{"type":"string","format":"uuid","description":"The sandbox these metrics belong to."}}},"SandboxMountResponse":{"oneOf":[{"type":"object","description":"Host-subpath bind mount.","required":["guest","options","stat_virtualization","host_permissions","type"],"properties":{"guest":{"type":"string"},"host_permissions":{"$ref":"#/components/schemas/HostPermissions"},"options":{"$ref":"#/components/schemas/MountOptions"},"quota_mib":{"type":["integer","null"],"format":"int32","minimum":0},"stat_virtualization":{"$ref":"#/components/schemas/StatVirtualization"},"type":{"type":"string","enum":["Bind"]}}},{"type":"object","description":"Named-volume mount.","required":["guest","options","stat_virtualization","host_permissions","type"],"properties":{"guest":{"type":"string"},"host_permissions":{"$ref":"#/components/schemas/HostPermissions"},"options":{"$ref":"#/components/schemas/MountOptions"},"stat_virtualization":{"$ref":"#/components/schemas/StatVirtualization"},"type":{"type":"string","enum":["Named"]}}},{"type":"object","description":"Guest-memory tmpfs.","required":["guest","options","type"],"properties":{"guest":{"type":"string"},"options":{"$ref":"#/components/schemas/MountOptions"},"size_mib":{"type":["integer","null"],"format":"int32","minimum":0},"type":{"type":"string","enum":["Tmpfs"]}}},{"type":"object","description":"Disk-image mount.","required":["guest","format","options","type"],"properties":{"format":{"$ref":"#/components/schemas/DiskImageFormat"},"fstype":{"type":["string","null"]},"guest":{"type":"string"},"options":{"$ref":"#/components/schemas/MountOptions"},"type":{"type":"string","enum":["DiskImage"]}}}],"description":"A mount, projected for the user: guest path + options, never the resolved\nvolume id / source."},"SandboxNetworkResponse":{"type":"object","description":"Network config, projected for the user. Secrets drop their vault path.","required":["enabled","ports","trust_host_cas"],"properties":{"dns":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DnsConfig"}]},"enabled":{"type":"boolean"},"interface":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/InterfaceOverrides"}]},"max_connections":{"type":["integer","null"],"minimum":0},"policy":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/NetworkPolicy"}]},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PublishedPortSpec"}},"secrets":{"type":"array","items":{"$ref":"#/components/schemas/SandboxSecretResponse"}},"tls":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TlsConfig"}]},"trust_host_cas":{"type":"boolean"}}},"SandboxPolicy":{"type":"object","description":"Sandbox lifecycle policy.","properties":{"ephemeral":{"type":"boolean","description":"Whether the sandbox is ephemeral.\n\nEphemeral sandboxes are one-off: the host runtime that owns the\nprocess removes the persisted DB row and on-disk state when the VM\nreaches a terminal status, and other host runtimes opportunistically\nclean up ephemeral leftovers from runtimes that died before they\ncould self-clean. Defaults to `false` (persistent); named and created\nsandboxes stay inspectable and restartable after they stop."},"idle_timeout_secs":{"type":["integer","null"],"format":"int64","description":"Idle timeout in seconds. `None` = no idle detection.","minimum":0},"max_duration_secs":{"type":["integer","null"],"format":"int64","description":"Hard cap on total sandbox lifetime in seconds. `None` = run forever.","minimum":0}}},"SandboxResponse":{"type":"object","description":"The API view of a [`Sandbox`]: an explicit allowlist of user-facing fields.\nInternal columns (registry selection, sync bookkeeping, resolved refs) never\nappear; the resolved spec surfaces only as the curated [`SandboxSpecResponse`].","required":["id","org_id","name","slug","status","ephemeral","created_at"],"properties":{"automatic_recovery_ends_at":{"type":["string","null"],"format":"date-time","description":"When an explicit recovery choice becomes necessary."},"created_at":{"type":"string","format":"date-time"},"ephemeral":{"type":"boolean"},"id":{"type":"string","format":"uuid"},"last_failure_message":{"type":["string","null"],"description":"Human-readable reason for the last failure."},"name":{"type":"string"},"org_id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"spec":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SandboxSpecResponse","description":"Curated projection of the resolved spec; absent until resolved."}]},"started_at":{"type":["string","null"],"format":"date-time","description":"Latest run's start time; `null` if the sandbox has never run."},"status":{"$ref":"#/components/schemas/SandboxStatus"},"status_reason":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SandboxStatusReason","description":"Scheduler condition while `status` is `starting`."}]},"stopped_at":{"type":["string","null"],"format":"date-time","description":"Latest run's stop time; `null` while open or never run."},"temporarily_unavailable_since":{"type":["string","null"],"format":"date-time","description":"When the current worker outage became user-visible."}}},"SandboxRuntimeOptions":{"type":"object","description":"Guest runtime options for a sandbox.","properties":{"cmd":{"type":["array","null"],"items":{"type":"string"},"description":"Image command override.","default":null},"disable_metrics_sample":{"type":"boolean","description":"Force-disable metrics sampling regardless of `metrics_sample_interval_ms`.","default":false},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Image entrypoint override.","default":null},"hostname":{"type":["string","null"],"description":"Guest hostname override.","default":null},"log_level":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SandboxLogLevel","description":"Runtime log verbosity."}],"default":null},"metrics_sample_interval_ms":{"type":["integer","null"],"format":"int64","description":"Metrics sampling interval in milliseconds. `None` disables sampling.","default":1000,"minimum":0},"scripts":{"type":"object","description":"Named scripts available inside the guest.","default":{},"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"shell":{"type":["string","null"],"description":"Default shell for scripts and interactive sessions.","default":null},"user":{"type":["string","null"],"description":"Guest user identity override.","default":null},"workdir":{"type":["string","null"],"description":"Working directory inside the guest.","default":null}}},"SandboxSecretResponse":{"type":"object","description":"A network secret, projected for the user: the env var, placeholder, and its\nallow-list / injection policy. The value isn't in the resolved spec at all,\nand the OpenBao vault path is never exposed.","required":["env_var","placeholder","allowed_hosts","injection"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"object"}},"env_var":{"type":"string"},"injection":{"type":"object"},"on_violation":{"type":"object"},"placeholder":{"type":"string"}}},"SandboxSpecResponse":{"type":"object","description":"A curated, user-facing projection of a sandbox's resolved spec. Built from\n[`ResolvedSandboxSpec`]; omits every internal resolution (secret\nvalues/vault paths, volume ids).","required":["resources","runtime","env","labels","rlimits","lifecycle","mounts","network"],"properties":{"env":{"type":"array","items":{"$ref":"#/components/schemas/EnvVar"},"description":"Environment variables."},"image":{"type":["string","null"],"description":"OCI image reference the sandbox boots; `null` for a non-OCI rootfs."},"labels":{"type":"object","description":"User-defined labels.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"lifecycle":{"$ref":"#/components/schemas/SandboxPolicy","description":"Lifecycle policy."},"mounts":{"type":"array","items":{"$ref":"#/components/schemas/SandboxMountResponse"},"description":"Volume mounts — guest path + options only; volume ids omitted."},"network":{"$ref":"#/components/schemas/SandboxNetworkResponse","description":"Network config — secret values/vault paths omitted."},"resources":{"$ref":"#/components/schemas/CloudSandboxResources","description":"CPU, memory, and writable-disk sizing."},"rlimits":{"type":"array","items":{"$ref":"#/components/schemas/Rlimit"},"description":"Resource limits."},"runtime":{"$ref":"#/components/schemas/SandboxRuntimeOptions","description":"Guest runtime options."}}},"SandboxStatus":{"type":"string","description":"Sandbox lifecycle status.","enum":["created","starting","running","temporarily_unavailable","recovery_decision_required","stopping","stopped","failed"]},"SandboxStatusReason":{"type":"string","description":"Why a submitted sandbox is still waiting for placement on a worker. Only\nmeaningful while `status` is `starting`.","enum":["scheduling","insufficient_capacity"]},"SandboxVolumeMount":{"type":"object","description":"Public mount context for one resolved sandbox-volume binding.","required":["volume_id","mount_path","read_only"],"properties":{"mount_path":{"type":"string","description":"Absolute path where the volume is mounted inside the guest."},"name":{"type":["string","null"],"description":"User-facing volume name; `None` identifies the organization host disk."},"read_only":{"type":"boolean","description":"Whether this binding is read-only."},"volume_id":{"type":"string","format":"uuid","description":"Resolved volume identifier, suitable for the volume metrics API."}}},"ScopedUpstreamCaCert":{"type":"object","description":"A CA certificate PEM file trusted only for matching upstream hosts.","required":["pattern","path"],"properties":{"path":{"type":"string","description":"Path to the CA certificate PEM file."},"pattern":{"type":"string","description":"Host pattern this CA applies to. Supports exact hosts and `*.suffix` wildcards."}}},"ScopedVerifyUpstream":{"type":"object","description":"An upstream certificate verification override for matching hosts.","required":["pattern","verify"],"properties":{"pattern":{"type":"string","description":"Host pattern this override applies to. Supports exact hosts and `*.suffix` wildcards."},"verify":{"type":"boolean","description":"Whether to verify matching upstream server certificates."}}},"SecretInjection":{"type":"object","description":"Where in the HTTP request a secret can be injected.","properties":{"basic_auth":{"type":"boolean","description":"Substitute in HTTP Basic Auth (default: true)."},"body":{"type":"boolean","description":"Substitute in request body (default: false).\n\nFixed-length HTTP/1 bodies up to 16 MiB update `Content-Length`;\nlarger fixed-length bodies are blocked. Chunked HTTP/1 bodies are\ndecoded and re-encoded with fresh chunk sizes. Encoded bodies pass\nthrough unchanged. HTTP/2 DATA-frame body substitution is not\nsupported; matching body placeholders are blocked."},"headers":{"type":"boolean","description":"Substitute in HTTP headers (default: true)."},"query_params":{"type":"boolean","description":"Substitute in URL query parameters (default: false)."}}},"SecurityProfile":{"type":"string","description":"Sandbox-level in-guest security profile.","enum":["default","restricted"]},"SetQuotaOverrideRequest":{"type":"object","description":"Request body for setting per-org quota overrides.","properties":{"max_concurrent_ephemeral_running":{"type":["integer","null"],"format":"int32"},"max_concurrent_persistent_running":{"type":["integer","null"],"format":"int32"},"max_disk_size_mib_per_sandbox":{"type":["integer","null"],"format":"int32"},"max_memory_mib_per_sandbox":{"type":["integer","null"],"format":"int32"},"max_sandboxes":{"type":["integer","null"],"format":"int32"},"max_total_storage_gib":{"type":["integer","null"],"format":"int32"},"max_uptime_minutes_per_sandbox":{"type":["integer","null"],"format":"int32"},"max_vcpus_per_sandbox":{"type":["integer","null"],"format":"int32"}}},"SlugAvailability":{"type":"object","description":"Whether a candidate slug is well-formed and currently unused. `valid` is\nthe format check; `available` is the global-uniqueness check (only meaningful\nwhen `valid`). `reason` explains an invalid format. Lets the create form\nguide the user before the sandbox is created.","required":["slug","valid","available"],"properties":{"available":{"type":"boolean"},"reason":{"type":["string","null"]},"slug":{"type":"string"},"valid":{"type":"boolean"}}},"SlugSuggestion":{"type":"object","description":"A suggested, currently-available sandbox slug to prefill the create form.","required":["slug"],"properties":{"slug":{"type":"string"}}},"StatVirtualization":{"type":"string","description":"Stat virtualization policy for a virtiofs-backed volume mount.\n\nSerializes/deserializes as the lowercase variant name (`\"strict\"`, `\"relaxed\"`, `\"off\"`) so persisted JSON aligns with the CLI grammar (`stat-virt=strict|relaxed|off`) and the NAPI string contract.","enum":["strict","relaxed","off"]},"StorageBreakdown":{"type":"object","description":"Per-volume durable-storage usage breakdown for an org over a window:\nper-(volume, day) rows plus a directory of the volumes they reference. The\nstorage sibling of [`UsageBreakdown`](crate::UsageBreakdown). Deleted volumes'\naccruals persist, so `rows` may reference `volume_id`s absent from `volumes`;\nthe client labels those as deleted.","required":["rows","volumes"],"properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/StorageDailyUsage"}},"volumes":{"type":"array","items":{"$ref":"#/components/schemas/VolumeIdentity"}}}},"StorageDailyUsage":{"type":"object","description":"Durable-storage usage for one volume on one UTC day, computed on read from\n`storage_accruals`. `mib_seconds` is Σ(used_mib × overlap_seconds) over the\nday; display converts to GiB-hours or an average GiB. Sum over days for a\nvolume's period total; sum over volumes for the daily series. The storage\nsibling of [`SandboxDailyUsage`](crate::SandboxDailyUsage).","required":["volume_id","day","mib_seconds"],"properties":{"day":{"type":"string","format":"date-time","description":"UTC midnight of the day this usage falls in."},"mib_seconds":{"type":"number","format":"double","description":"Σ(used_mib × overlap_seconds) for this volume on this day."},"volume_id":{"type":"string","format":"uuid"}}},"TlsConfig":{"type":"object","description":"TLS interception configuration. Carried in [`NetworkSpec::tls`](NetworkSpec).\n\nThe local network engine terminates TCP at its in-process stack, so TLS MITM\nis handled by proxy tasks — these fields configure which ports/domains are\nintercepted and how the interception CA is sourced.","properties":{"block_quic_on_intercept":{"type":"boolean","description":"Drop UDP to intercepted ports when TLS interception is active, forcing\nQUIC traffic to fall back to TCP/TLS."},"bypass":{"type":"array","items":{"type":"string"},"description":"Domains to bypass (no MITM). Supports exact match and `*.suffix` wildcards."},"cache":{"$ref":"#/components/schemas/CertCacheConfig","description":"Per-domain certificate cache configuration."},"enabled":{"type":"boolean","description":"Whether TLS interception is enabled."},"intercept_ca":{"$ref":"#/components/schemas/InterceptCaConfig","description":"Interception CA configuration. The TLS proxy uses this CA to sign\nper-domain certs it presents to the guest during interception."},"intercepted_ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"TCP ports subject to TLS interception (default: `[443]`)."},"scoped_upstream_ca_cert":{"type":"array","items":{"$ref":"#/components/schemas/ScopedUpstreamCaCert"},"description":"Host-scoped CA certificate PEM files to trust for upstream server verification."},"scoped_verify_upstream":{"type":"array","items":{"$ref":"#/components/schemas/ScopedVerifyUpstream"},"description":"Host-scoped upstream verification overrides."},"upstream_ca_cert":{"type":"array","items":{"type":"string"},"description":"CA certificate PEM files to trust for upstream server verification."},"verify_upstream":{"type":"boolean","description":"Whether to verify the upstream server's TLS certificate."}}},"UpdateMeRequest":{"type":"object","description":"PATCH /v1/users/me","properties":{"avatar_url":{"type":["string","null"]},"display_name":{"type":["string","null"]}}},"UpdateMemberRoleRequest":{"type":"object","description":"PATCH /v1/orgs/:slug/members/:user_id — update a member's role.","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/OrgRole"}}},"UpdateOrgRequest":{"type":"object","description":"PATCH /v1/orgs/:slug — update an organization.","properties":{"mfa_required":{"type":["boolean","null"]},"name":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"UpdateSandboxRequest":{"type":"object","description":"Request body for `PATCH /v1/orgs/:slug/sandboxes/:id` — rename a sandbox.\nEach field updates only when present; omit one to leave it unchanged.\n`name` is the per-org display label; `slug` is the globally-unique SSH\naddress handle (changing it breaks existing `ssh <old-slug>@msb.run`).","properties":{"name":{"type":["string","null"],"description":"New per-org display name. Omit to leave unchanged."},"slug":{"type":["string","null"],"description":"New globally-unique slug (the SSH username token). Omit to leave unchanged."}}},"UpdateVolumeRequest":{"type":"object","description":"PATCH /v1/orgs/{slug}/volumes/{id} — update the cap and/or labels (#496).\n\nEvery field is independently optional: an **omitted** field is left unchanged.\n`capacity_gib` uses the double-`Option` distinction — omit to leave as-is,\nexplicit `null` to clear the cap, a number to set it.","properties":{"capacity_gib":{"type":["integer","null"],"format":"int32","description":"New per-volume storage cap in GiB. Omitted = unchanged; `null` = clear the\ncap (back to no per-volume limit); a value sets it. A set value must be\n`>= 1` and `<= the org's storage cap`.","minimum":0},"labels":{"type":["object","null"],"description":"Replacement label set. Omitted = unchanged; an object replaces the labels\nwholesale (an empty object clears them). Reserved-prefix keys are rejected.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}},"UpsertOidcConfigRequest":{"type":"object","description":"PUT /v1/orgs/:slug/oidc — create or update OIDC config.","required":["issuer_url","client_id","client_secret"],"properties":{"allowed_domains":{"type":"array","items":{"type":"string"}},"client_id":{"type":"string"},"client_secret":{"type":"string"},"issuer_url":{"type":"string"}}},"UpsertRegistryCredentialRequest":{"type":"object","description":"PUT /v1/orgs/{slug}/registries","required":["registry_host","username","password"],"properties":{"password":{"type":"string","description":"Password or access token. Stored in OpenBao — never persisted to the DB."},"registry_host":{"type":"string","description":"Registry host, e.g. `ghcr.io` or `localhost:5000`. Canonicalized\nserver-side; Docker Hub aliases fold to `docker.io`."},"username":{"type":"string","description":"Registry username."}}},"UsageBreakdown":{"type":"object","description":"Compute-on-read usage breakdown for an org over a window: per-(sandbox, day)\nquantity rows plus a directory of the sandboxes they reference. The frontend\ngroups `rows` by sandbox (for the per-sandbox table) or by day (for the\nchart) and labels them via `sandboxes`.","required":["rows","sandboxes"],"properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/SandboxDailyUsage"}},"sandboxes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxIdentity"}}}},"UsageDailyPoint":{"type":"object","description":"One day's metered quantity for a single billable metric — the unit of a\nusage time-series chart. Cost is intentionally omitted: invoices are\nperiod-aggregated, so a per-day dollar figure would have to be derived.","required":["date","metric","quantity"],"properties":{"date":{"type":"string","format":"date-time","description":"Start of the day window (UTC)."},"metric":{"type":"string","description":"Billable-metric name this quantity belongs to."},"quantity":{"type":"number","format":"double"}}},"UsageLineItem":{"type":"object","description":"A single line item in a usage summary.","required":["name","quantity","unit","amount_cents"],"properties":{"amount_cents":{"type":"integer","format":"int64"},"name":{"type":"string"},"quantity":{"type":"number","format":"double"},"unit":{"type":"string"}}},"UsageSummary":{"type":"object","description":"Usage summary from the billing provider.","required":["period_start","period_end","line_items","total_cents"],"properties":{"daily":{"type":"array","items":{"$ref":"#/components/schemas/UsageDailyPoint"},"description":"Per-day metered quantities for charting. One entry per (day, metric).\nEmpty when no daily series is available (e.g. provider error)."},"line_items":{"type":"array","items":{"$ref":"#/components/schemas/UsageLineItem"},"description":"Period-aggregated breakdown — one entry per billable metric / charge."},"period_end":{"type":"string","format":"date-time"},"period_start":{"type":"string","format":"date-time"},"projected_spend_cents":{"type":"integer","format":"int64","description":"End-of-period spend projection: `total_cents` linearly extrapolated over\nthe billing period. Equals `total_cents` when the period can't be\nextrapolated (no future end, or zero elapsed). Never below `total_cents`."},"storage_gib":{"type":["number","null"],"format":"double","description":"Current durable-storage usage (GiB) for the org, from the latest hourly\nreading. `None` when storage hasn't been sampled (juicefs-ops disabled or\nno volumes). Drives the storage allowance bar; cost is in `line_items`."},"total_cents":{"type":"integer","format":"int64"}}},"User":{"type":"object","description":"An active registered human user.\n\nRepository methods returning this type exclude soft-deleted rows, so email\nis always present. Use [`UserRecord`] for lookups that include tombstones.","required":["id","email","email_verified","status","created_at","updated_at"],"properties":{"avatar_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":["string","null"]},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/UserStatus"},"updated_at":{"type":"string","format":"date-time"}}},"UserSession":{"type":"object","description":"Active user session. One user can have multiple sessions (multi-device).","required":["id","user_id","expires_at","created_at","last_active_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"last_active_at":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]},"user_id":{"type":"string","format":"uuid"}}},"UserStatus":{"type":"string","description":"User account status.","enum":["active","suspended","pending_verification"]},"VerifyEmailRequest":{"type":"object","description":"POST /v1/auth/verify-email","required":["token"],"properties":{"token":{"type":"string"}}},"VolumeIdentity":{"type":"object","description":"Minimal volume display info — the directory that turns the `volume_id`s in a\n[`StorageBreakdown`](crate::StorageBreakdown)'s rows into human labels. A\ndeleted volume's accruals outlive its row, so a breakdown may reference ids\nabsent from this directory; the client labels those as deleted.","required":["id"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":["string","null"],"description":"`None` for the host volume (nameless)."}}},"VolumeKind":{"type":"string","description":"What kind of volume this is — its storage source / role. The host volume is\nthe org's single shared \"host disk\"; managed volumes are user-created, named,\nplatform-provisioned (JuiceFS over our object store). (A future `External`\nvariant — bring-your-own S3/GCS — is intentionally out of scope for now.)","enum":["host","managed"]},"VolumeMetricsResponse":{"type":"object","description":"Per-volume JuiceFS performance metrics over a time range.","required":["volume_id","range","metrics"],"properties":{"metrics":{"type":"object","description":"Metric key → aggregate series across every worker mounting the volume.\nAn empty series means \"no data in range\".","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/MetricSeries"}},"propertyNames":{"type":"string"}},"range":{"$ref":"#/components/schemas/MetricsRange","description":"The resolved query window."},"volume_id":{"type":"string","format":"uuid","description":"The volume these metrics belong to."}}},"VolumeResponse":{"type":"object","description":"Volume metadata returned in list/create responses. The GCS storage path is\nderived (not stored) and never exposed.","required":["id","kind","storage","status","labels","created_at","updated_at"],"properties":{"capacity_bytes":{"type":["integer","null"],"format":"int64","description":"The volume's configured per-volume storage cap in bytes, or `null` when\nno cap is set (#496). Derived from the stored `capacity_gib` (the user's\nconfigured intent) — the effective ceiling is `min(this, org cap)`.","minimum":0},"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"kind":{"$ref":"#/components/schemas/VolumeKind","description":"`host` — the org's shared host disk (not deletable); `managed` — a\nuser-created named volume."},"labels":{"type":"object","description":"User-defined labels (empty object when none set).","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":["string","null"],"description":"User-facing name. `null` for the host volume (it has no name; it's\nidentified by `kind`)."},"status":{"$ref":"#/components/schemas/VolumeStatus"},"storage":{"$ref":"#/components/schemas/VolumeType","description":"How the volume is physically backed (`block` today)."},"updated_at":{"type":"string","format":"date-time"},"used_bytes":{"type":["integer","null"],"format":"int64","description":"Bytes currently used under this volume's subtree. `null` when usage is\nunavailable — the usage service is disabled or unreachable (list degrades\ngracefully rather than failing) — or on create/delete, which don't sample\nit.","minimum":0}}},"VolumeStatus":{"type":"string","description":"Lifecycle status of a volume.","enum":["active","deleting"]},"VolumeType":{"type":"string","description":"How a volume is physically backed — distinct from [`VolumeKind`] (ownership).\nEvery volume is `Block` today; the enum exists so future backings can be added\n(and reported to the SDK) without another schema change.","enum":["block"]}},"securitySchemes":{"api_key":{"type":"http","scheme":"bearer","description":"Organization API key (msb_…) — org-scoped programmatic access."},"bearer":{"type":"http","scheme":"bearer","description":"Personal access token (msb_pat_…) or session JWT — the credential an agent acts with on a user's behalf."},"billing_operator":{"type":"http","scheme":"bearer","description":"VPC-only billing operator credential used by internal administration tools."},"session":{"type":"http","scheme":"bearer","description":"Browser session JWT — interactive dashboard use only. Not available to agents or programmatic API consumers."}}},"security":[{"bearer":[]},{"api_key":[]}],"tags":[{"name":"health","description":"Health and readiness probes"},{"name":"auth","description":"Authentication (register, login, tokens)"},{"name":"users","description":"User profile and session management"},{"name":"oauth","description":"OAuth provider authentication"},{"name":"oidc","description":"OIDC enterprise SSO authentication"},{"name":"organizations","description":"Organization CRUD"},{"name":"members","description":"Organization member management"},{"name":"invites","description":"Organization invitations"},{"name":"oidc-config","description":"Organization OIDC configuration"},{"name":"registry-credentials","description":"Private OCI registry credentials"},{"name":"volumes","description":"Persistent per-org storage volumes"},{"name":"api-keys","description":"API key management"},{"name":"personal-access-tokens","description":"Personal access token management (user-scoped)"},{"name":"sandboxes","description":"Sandbox lifecycle management"},{"name":"audit-log","description":"Audit log and usage events"},{"name":"quotas","description":"Quota usage and per-org overrides"},{"name":"billing","description":"Billing, plans, invoices, and payment methods"}]}