{"openapi":"3.1.0","info":{"title":"makefx.app API","version":"0.0.0","description":"A pay-per-asset media workshop on Cloudflare where a person and their agent make images, video, and audio on one canvas.\n\nReads need an access token with the `read` scope, writes the `write` scope, and routes that manage the account itself accept only the browser session. Tokens come from the OAuth 2.1 authorization server described in `components.securitySchemes`; client registration is open and immediate.\n\nVersioning is by date. The current version is 2026-09-10; send it as `API-Version` to pin a client, omit it for the current version. Every response under /api carries `API-Version` naming the version that answered; an unknown version is refused with 400 `unsupported_version`. A superseded version keeps answering for at least 90 days with `Deprecation` and `Sunset` headers (RFC 9745, RFC 8594) before it is removed.\n\nRate limits are per 60 seconds: 1200 requests per address for the API, with tighter buckets on the OAuth endpoints. Every response names the policy it passed under in `RateLimit-Policy`; a refusal is 429 with `Retry-After`.\n\nEvery error is the `ApiError` shape: an `error` code or sentence, and `error_description` when there is more to say. A request without a valid token answers 401 with a `WWW-Authenticate` header naming the protected resource metadata. Developer documentation: https://stage.makefx.app/developers.","contact":{"name":"Aleksei Krasnoperov","url":"https://krasnoperov.me"}},"servers":[{"url":"https://stage.makefx.app","description":"makefx.app"}],"externalDocs":{"url":"https://stage.makefx.app/developers","description":"Developer portal"},"tags":[{"name":"Service","description":"The API index and health checks. Nothing here needs a token."},{"name":"Auth","description":"Browser sign-in with Google, sessions, and the apps a person has connected."},{"name":"OAuth","description":"The OAuth 2.1 authorization server: discovery, client registration, consent and tokens."},{"name":"User","description":"The signed-in person's profile."},{"name":"Models","description":"The model catalog and the inputs, references and prices it declares."},{"name":"Space","description":"Account-scoped spaces available to the signed-in person."},{"name":"Asset","description":"Quoted, generated and polled media assets inside an authorized space."},{"name":"Link","description":"Manual labeled edges between active assets in an authorized space."}],"components":{"schemas":{"ApiError":{"type":"object","properties":{"error":{"type":"string","description":"A short code or sentence naming what went wrong"},"error_description":{"type":"string","description":"More for a person, when the code alone would not do"},"retryable":{"type":"boolean","description":"Whether repeating the same request may succeed"},"details":{"type":"object","additionalProperties":{},"description":"Machine-readable error context"}},"required":["error"]}},"parameters":{"ApiVersion":{"name":"API-Version","in":"header","required":false,"description":"The API version the client was written against. Omit it for the current version, 2026-09-10. The response carries the same header, naming the version that answered.","schema":{"type":"string","enum":["2026-09-10"]}}},"securitySchemes":{"oauth2":{"type":"oauth2","description":"OAuth 2.1 authorization code with PKCE (S256), issued by this deployment. Register a client at the registration endpoint or present a Client ID Metadata Document, then send the person to authorize. Metadata: /.well-known/oauth-authorization-server.","flows":{"authorizationCode":{"authorizationUrl":"https://stage.makefx.app/api/oauth/authorize","tokenUrl":"https://stage.makefx.app/api/oauth/token","refreshUrl":"https://stage.makefx.app/api/oauth/token","scopes":{"openid":"Confirm who you are","profile":"See your name","email":"See your email address","read":"Read your data","write":"Change your data on your behalf"}}}},"session":{"type":"apiKey","in":"cookie","name":"auth_token","description":"The browser session set by signing in with Google. Routes that manage the account itself accept only this, never an app token."},"registrationToken":{"type":"http","scheme":"bearer","description":"The registration access token returned by client registration (RFC 7592). It manages that one registration and nothing else."}}},"paths":{"/api":{"get":{"operationId":"apiIndex","summary":"API index","description":"Where this deployment's OpenAPI document, developer documentation, authorization metadata, MCP endpoint and health check are, as absolute URLs. Needs no token.","tags":["Service"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"},"description":{"type":"string"},"openapi":{"type":"string","format":"uri"},"documentation":{"type":"string","format":"uri"},"health":{"type":"string","format":"uri"},"mcp":{"type":"object","properties":{"endpoint":{"type":"string","format":"uri"},"serverCard":{"type":"string","format":"uri"}},"required":["endpoint","serverCard"]},"authorization":{"type":"object","properties":{"authorizationServer":{"type":"string","format":"uri"},"protectedResource":{"type":"string","format":"uri"}},"required":["authorizationServer","protectedResource"]},"catalog":{"type":"string","format":"uri"},"llms":{"type":"string","format":"uri"}},"required":["name","version","description","openapi","documentation","health","mcp","authorization","catalog","llms"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/health":{"get":{"operationId":"healthCheck","summary":"Health check","description":"Reports that the service is reachable and which environment answered. Needs no token.","tags":["Service"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"environment":{"type":"string"}},"required":["status"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/hello":{"get":{"operationId":"hello","summary":"Hello","description":"A fixed greeting that proves the API foundation is wired. Needs no token.","tags":["Service"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/.well-known/openid-configuration":{"get":{"operationId":"oauthDiscovery","summary":"OpenID discovery","description":"The authorization server metadata under its OpenID name. The same document as /.well-known/oauth-authorization-server.","tags":["OAuth"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"issuer":{"type":"string","format":"uri"},"authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"registration_endpoint":{"type":"string","format":"uri"},"revocation_endpoint":{"type":"string","format":"uri"},"jwks_uri":{"type":"string","format":"uri"},"response_types_supported":{"type":"array","items":{"type":"string"}},"grant_types_supported":{"type":"array","items":{"type":"string"}},"code_challenge_methods_supported":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"}},"revocation_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"}},"scopes_supported":{"type":"array","items":{"type":"string"}},"client_id_metadata_document_supported":{"type":"boolean"}},"required":["issuer","authorization_endpoint","token_endpoint","registration_endpoint","revocation_endpoint","jwks_uri","response_types_supported","grant_types_supported","code_challenge_methods_supported","token_endpoint_auth_methods_supported","revocation_endpoint_auth_methods_supported","scopes_supported","client_id_metadata_document_supported"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"operationId":"oauthAuthorizationServerMetadata","summary":"Authorization server metadata","description":"RFC 8414: the endpoints, grant types, PKCE methods and scopes of this issuer.","tags":["OAuth"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"issuer":{"type":"string","format":"uri"},"authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"registration_endpoint":{"type":"string","format":"uri"},"revocation_endpoint":{"type":"string","format":"uri"},"jwks_uri":{"type":"string","format":"uri"},"response_types_supported":{"type":"array","items":{"type":"string"}},"grant_types_supported":{"type":"array","items":{"type":"string"}},"code_challenge_methods_supported":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"}},"revocation_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"}},"scopes_supported":{"type":"array","items":{"type":"string"}},"client_id_metadata_document_supported":{"type":"boolean"}},"required":["issuer","authorization_endpoint","token_endpoint","registration_endpoint","revocation_endpoint","jwks_uri","response_types_supported","grant_types_supported","code_challenge_methods_supported","token_endpoint_auth_methods_supported","revocation_endpoint_auth_methods_supported","scopes_supported","client_id_metadata_document_supported"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"operationId":"oauthProtectedResource","summary":"Protected resource metadata","description":"RFC 9728: which authorization server protects the API, and which scopes it understands.","tags":["OAuth"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"resource":{"type":"string","format":"uri"},"resource_name":{"type":"string"},"authorization_servers":{"type":"array","items":{"type":"string","format":"uri"}},"bearer_methods_supported":{"type":"array","items":{"type":"string"}},"scopes_supported":{"type":"array","items":{"type":"string"}},"jwks_uri":{"type":"string","format":"uri"},"resource_documentation":{"type":"string","format":"uri"}},"required":["resource","resource_name","authorization_servers","bearer_methods_supported","scopes_supported","jwks_uri","resource_documentation"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/.well-known/oauth-protected-resource/mcp":{"get":{"operationId":"oauthProtectedResourceMcp","summary":"MCP protected resource metadata","description":"RFC 9728 for the MCP endpoint, which is its own resource. A client refused by /mcp is pointed here to find the authorization server.","tags":["OAuth"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"resource":{"type":"string","format":"uri"},"resource_name":{"type":"string"},"authorization_servers":{"type":"array","items":{"type":"string","format":"uri"}},"bearer_methods_supported":{"type":"array","items":{"type":"string"}},"scopes_supported":{"type":"array","items":{"type":"string"}},"jwks_uri":{"type":"string","format":"uri"},"resource_documentation":{"type":"string","format":"uri"}},"required":["resource","resource_name","authorization_servers","bearer_methods_supported","scopes_supported","jwks_uri","resource_documentation"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/.well-known/jwks.json":{"get":{"operationId":"oauthJwks","summary":"Signing keys","description":"The JSON Web Key Set that verifies the tokens this issuer signs.","tags":["OAuth"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","properties":{"kid":{"type":"string"},"alg":{"type":"string"},"use":{"type":"string"}},"required":["kid","alg","use"],"additionalProperties":{}}}},"required":["keys"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/oauth/authorize":{"get":{"operationId":"oauthAuthorize","summary":"Authorization endpoint","description":"Starts an authorization code flow with PKCE (S256). Sends the person to sign in and consent, then back to the redirect URI with a code.","tags":["OAuth"],"parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"client_id","in":"query"},{"schema":{"type":"string","format":"uri"},"required":true,"name":"redirect_uri","in":"query"},{"schema":{"type":"string","enum":["code"]},"required":true,"name":"response_type","in":"query"},{"schema":{"type":"string","minLength":43,"maxLength":128},"required":true,"name":"code_challenge","in":"query"},{"schema":{"type":"string","enum":["S256"]},"required":true,"name":"code_challenge_method","in":"query"},{"schema":{"type":"string"},"required":false,"name":"scope","in":"query"},{"schema":{"type":"string","format":"uri"},"required":false,"name":"resource","in":"query"},{"schema":{"type":"string"},"required":false,"name":"state","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"302":{"description":"Sends the browser to the next step of the flow; there is no body","headers":{"Location":{"description":"Where the browser goes next","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"unauthorized_client: the client_id is not registered here","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/oauth/token":{"post":{"operationId":"oauthToken","summary":"Token endpoint","description":"Exchanges an authorization code, or a refresh token, for tokens. Form-encoded as RFC 6749 requires; JSON is accepted too.","tags":["OAuth"],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"oneOf":[{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code"]},"code":{"type":"string","minLength":1},"code_verifier":{"type":"string","minLength":43,"maxLength":128},"redirect_uri":{"type":"string","format":"uri"},"client_id":{"type":"string","minLength":1},"client_secret":{"type":"string","minLength":1},"resource":{"type":"string","format":"uri"}},"required":["grant_type","code","code_verifier","redirect_uri"]},{"type":"object","properties":{"grant_type":{"type":"string","enum":["refresh_token"]},"refresh_token":{"type":"string","minLength":1},"scope":{"type":"string"},"client_id":{"type":"string","minLength":1},"client_secret":{"type":"string","minLength":1},"resource":{"type":"string","format":"uri"}},"required":["grant_type","refresh_token"]}]}},"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code"]},"code":{"type":"string","minLength":1},"code_verifier":{"type":"string","minLength":43,"maxLength":128},"redirect_uri":{"type":"string","format":"uri"},"client_id":{"type":"string","minLength":1},"client_secret":{"type":"string","minLength":1},"resource":{"type":"string","format":"uri"}},"required":["grant_type","code","code_verifier","redirect_uri"]},{"type":"object","properties":{"grant_type":{"type":"string","enum":["refresh_token"]},"refresh_token":{"type":"string","minLength":1},"scope":{"type":"string"},"client_id":{"type":"string","minLength":1},"client_secret":{"type":"string","minLength":1},"resource":{"type":"string","format":"uri"}},"required":["grant_type","refresh_token"]}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string"},"expires_in":{"type":"number"},"scope":{"type":"string"},"refresh_token":{"type":"string"},"refresh_token_expires_in":{"type":"number"},"user":{"type":["object","null"],"properties":{"id":{"type":"number"},"email":{"type":"string","format":"email"},"name":{"type":"string"}},"required":["id"]}},"required":["access_token","token_type","expires_in","scope","user"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"invalid_client: the client credentials were missing or wrong","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/oauth/revoke":{"post":{"operationId":"oauthRevoke","summary":"Revoke a token","description":"RFC 7009. Revoking a refresh token ends its grant; the client must authorize again. Answers 200 with an empty object whether or not the token was known, as the RFC requires.","tags":["OAuth"],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":1},"token_type_hint":{"type":"string","enum":["access_token","refresh_token"]},"client_id":{"type":"string","minLength":1},"client_secret":{"type":"string","minLength":1}},"required":["token"]}},"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":1},"token_type_hint":{"type":"string","enum":["access_token","refresh_token"]},"client_id":{"type":"string","minLength":1},"client_secret":{"type":"string","minLength":1}},"required":["token"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"invalid_client: the client credentials were missing or wrong","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/oauth/authorize/request":{"get":{"operationId":"oauthApprovalRequest","summary":"Pending consent request","description":"What the consent page shows: the client and the scopes awaiting the signed-in person's decision. Browser session only.","tags":["OAuth"],"security":[{"session":[]}],"parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"request","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string"},"clientName":{"type":"string"},"redirectUri":{"type":"string","format":"uri"},"scopes":{"type":"array","items":{"type":"string"}},"user":{"type":"object","properties":{"id":{"type":"number"},"email":{"type":"string","format":"email"}},"required":["id","email"]}},"required":["clientId","clientName","redirectUri","scopes","user"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/oauth/authorize/decision":{"post":{"operationId":"oauthApprovalDecision","summary":"Decide a consent request","description":"Approves or declines a pending request. Approval issues the authorization code. Browser session only.","tags":["OAuth"],"security":[{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string","minLength":1},"approved":{"type":"boolean"}},"required":["request_id","approved"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"redirectUrl":{"type":"string","format":"uri"}},"required":["redirectUrl"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/oauth/register":{"post":{"operationId":"oauthClientRegister","summary":"Register a client","description":"RFC 7591 dynamic registration. Open and immediate: the response carries the client_id and a registration access token for managing the registration.","tags":["OAuth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"scope":{"type":"string"},"token_endpoint_auth_method":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"scope":{"type":"string"},"token_endpoint_auth_method":{"type":"string"},"client_id_issued_at":{"type":"number"},"client_secret_expires_at":{"type":"number"},"registration_client_uri":{"type":"string","format":"uri"},"registration_access_token":{"type":"string"},"client_secret":{"type":"string"}},"required":["client_id","client_name","redirect_uris","grant_types","response_types","scope","token_endpoint_auth_method","client_id_issued_at","client_secret_expires_at","registration_client_uri"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/oauth/register/{clientId}":{"get":{"operationId":"oauthClientGet","summary":"Read a client registration","description":"RFC 7592. The registration as it stands, for the client that holds its registration access token.","tags":["OAuth"],"security":[{"registrationToken":[]}],"parameters":[{"schema":{"type":"string","description":"clientId path parameter"},"required":true,"description":"clientId path parameter","name":"clientId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"scope":{"type":"string"},"token_endpoint_auth_method":{"type":"string"},"client_id_issued_at":{"type":"number"},"client_secret_expires_at":{"type":"number"},"registration_client_uri":{"type":"string","format":"uri"},"registration_access_token":{"type":"string"},"client_secret":{"type":"string"}},"required":["client_id","client_name","redirect_uris","grant_types","response_types","scope","token_endpoint_auth_method","client_id_issued_at","client_secret_expires_at","registration_client_uri"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"put":{"operationId":"oauthClientUpdate","summary":"Update a client registration","description":"RFC 7592. Replaces the registered metadata; the client_id stays.","tags":["OAuth"],"security":[{"registrationToken":[]}],"parameters":[{"schema":{"type":"string","description":"clientId path parameter"},"required":true,"description":"clientId path parameter","name":"clientId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"scope":{"type":"string"},"token_endpoint_auth_method":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"scope":{"type":"string"},"token_endpoint_auth_method":{"type":"string"},"client_id_issued_at":{"type":"number"},"client_secret_expires_at":{"type":"number"},"registration_client_uri":{"type":"string","format":"uri"},"registration_access_token":{"type":"string"},"client_secret":{"type":"string"}},"required":["client_id","client_name","redirect_uris","grant_types","response_types","scope","token_endpoint_auth_method","client_id_issued_at","client_secret_expires_at","registration_client_uri"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"operationId":"oauthClientDelete","summary":"Delete a client registration","description":"RFC 7592. Removes the registration; tokens issued to the client stop working.","tags":["OAuth"],"security":[{"registrationToken":[]}],"parameters":[{"schema":{"type":"string","description":"clientId path parameter"},"required":true,"description":"clientId path parameter","name":"clientId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"204":{"description":"Done; there is no body"},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/auth/session":{"get":{"operationId":"authSession","summary":"Current session","description":"The signed-in user of the presented session cookie or bearer token, or null when there is none. Never fails for an anonymous caller.","tags":["Auth"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":["object","null"],"properties":{"id":{"type":"string"},"email":{"type":"string","format":"email"},"name":{"type":"string"}},"required":["id","email","name"]},"config":{"type":"object","properties":{"googleClientId":{"type":"string"},"environment":{"type":"string"}},"required":["googleClientId"]}},"required":["user","config"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/auth/google/login":{"get":{"operationId":"authGoogleLogin","summary":"Start Google sign-in","description":"Redirects the browser to Google. The optional redirect query names the local path to return to afterwards.","tags":["Auth"],"parameters":[{"schema":{"type":"string"},"required":false,"name":"return_to","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"302":{"description":"Sends the browser to the next step of the flow; there is no body","headers":{"Location":{"description":"Where the browser goes next","schema":{"type":"string","format":"uri"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/auth/logout":{"post":{"operationId":"authLogout","summary":"Sign out","description":"Ends the current browser session and clears its cookie.","tags":["Auth"],"security":[{"session":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/auth/logout/all":{"post":{"operationId":"authLogoutAll","summary":"Sign out everywhere","description":"Ends every session of the signed-in user. Accepts a browser session only, never an app token.","tags":["Auth"],"security":[{"session":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"number"}},"required":["revoked"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/auth/grants":{"get":{"operationId":"authGrantsList","summary":"List connected apps","description":"The OAuth grants the signed-in user has given: the client, the scopes, and when each was created and last used. Browser session only.","tags":["Auth"],"security":[{"session":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"grants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"clientName":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"number"},"lastUsedAt":{"type":"number"},"expiresAt":{"type":"number"},"revokedAt":{"type":["number","null"]}},"required":["id","clientId","clientName","scopes","createdAt","lastUsedAt","expiresAt","revokedAt"]}}},"required":["grants"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]},"delete":{"operationId":"authGrantsRevokeAll","summary":"Revoke all connected apps","description":"Revokes every grant of the signed-in user. Browser session only.","tags":["Auth"],"security":[{"session":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"number"}},"required":["revoked"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/auth/grants/{grantId}":{"delete":{"operationId":"authGrantRevoke","summary":"Revoke a connected app","description":"Revokes one grant. Every token issued under it stops working on its next use. Browser session only.","tags":["Auth"],"security":[{"session":[]}],"parameters":[{"schema":{"type":"string","description":"grantId path parameter"},"required":true,"description":"grantId path parameter","name":"grantId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"number"}},"required":["revoked"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/user/profile":{"get":{"operationId":"userProfileGet","summary":"Get profile","description":"The signed-in user: id, email and display name.","tags":["User"],"security":[{"oauth2":["read"]},{"session":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","format":"email"},"name":{"type":"string"}},"required":["id","email","name"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]},"patch":{"operationId":"userProfileUpdate","summary":"Update profile","description":"Changes the display name of the signed-in user.","tags":["User"],"security":[{"oauth2":["write"]},{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1}},"required":["name"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"user":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","format":"email"},"name":{"type":"string"}},"required":["id","email","name"]}},"required":["success","user"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/accounts":{"get":{"operationId":"accountsList","summary":"List accounts","description":"Lists the caller's active personal and team account memberships, personal first.","tags":["User"],"security":[{"oauth2":["read"]},{"session":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"accounts":{"type":"array","items":{"type":"object","properties":{"account_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"kind":{"type":"string","enum":["personal","team"]},"name":{"type":"string"},"role":{"type":"string","enum":["owner","editor","viewer"]}},"required":["account_id","kind","name","role"],"additionalProperties":false}}},"required":["accounts"],"additionalProperties":false}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]},"post":{"operationId":"accountCreate","summary":"Create team account","description":"Creates one zero-balance team account with the caller as its active owner.","tags":["User"],"security":[{"oauth2":["write"]},{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"object","properties":{"account_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"kind":{"type":"string","enum":["personal","team"]},"name":{"type":"string"},"role":{"type":"string","enum":["owner","editor","viewer"]}},"required":["account_id","kind","name","role"],"additionalProperties":false}},"required":["account"],"additionalProperties":false}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/account":{"get":{"operationId":"accountGet","summary":"Get account","description":"Reads one account's available balance and active credit holds for an active member.","tags":["User"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"Defaults to the caller's personal account."},"required":false,"description":"Defaults to the caller's personal account.","name":"account_id","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string"},"role":{"type":"string","enum":["owner","editor","viewer"]},"balance_credits":{"type":"integer"},"held_credits":{"type":"integer","minimum":0},"topup_url":{"type":["string","null"],"format":"uri"},"own_keys":{"type":"array","items":{"type":"string","enum":["google_ai","openai","fal","replicate","elevenlabs"]}}},"required":["account_id","role","balance_credits","held_credits","topup_url","own_keys"],"additionalProperties":false}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/accounts/{accountId}/provider-keys":{"get":{"operationId":"accountProviderKeysList","summary":"List account provider keys","description":"Lists active provider identifiers, four-character hints, and the ElevenLabs voice mirror an account's owner may act on.","tags":["User"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string","enum":["google_ai","openai","fal","replicate","elevenlabs"]},"hint":{"type":"string","minLength":4,"maxLength":4},"created_at":{"type":"integer","minimum":0},"voice_mirror":{"type":["object","null"],"properties":{"active_voice_count":{"type":"integer","minimum":0},"synced_at":{"type":"integer","minimum":0}},"required":["active_voice_count","synced_at"],"additionalProperties":false}},"required":["provider","hint","created_at"],"additionalProperties":false}}},"required":["keys"],"additionalProperties":false}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/accounts/{accountId}/provider-keys/{provider}":{"put":{"operationId":"accountProviderKeySet","summary":"Set an account provider key","description":"Validates and replaces one provider credential for an account owner without returning it.","tags":["User"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"provider path parameter"},"required":true,"description":"provider path parameter","name":"provider","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"credential":{"type":"string","minLength":4,"maxLength":16384}},"required":["credential"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","enum":["google_ai","openai","fal","replicate","elevenlabs"]},"hint":{"type":"string","minLength":4,"maxLength":4},"created_at":{"type":"integer","minimum":0},"voice_mirror":{"type":["object","null"],"properties":{"active_voice_count":{"type":"integer","minimum":0},"synced_at":{"type":"integer","minimum":0}},"required":["active_voice_count","synced_at"],"additionalProperties":false},"voice_sync":{"oneOf":[{"type":"object","properties":{"status":{"type":"string","enum":["failed"]}},"required":["status"],"additionalProperties":false},{"type":"object","properties":{"status":{"type":"string","enum":["synced"]},"active_voice_count":{"type":"integer","minimum":0},"synced_at":{"type":"integer","minimum":0}},"required":["status","active_voice_count","synced_at"],"additionalProperties":false}]}},"required":["provider","hint","created_at"],"additionalProperties":false}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"operationId":"accountProviderKeyRevoke","summary":"Revoke an account provider key","description":"Soft-revokes the active provider credential. Repeating the request has no effect.","tags":["User"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"provider path parameter"},"required":true,"description":"provider path parameter","name":"provider","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","enum":["google_ai","openai","fal","replicate","elevenlabs"]},"revoked":{"type":"boolean"}},"required":["provider","revoked"],"additionalProperties":false}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/accounts/{accountId}/provider-keys/elevenlabs/refresh":{"post":{"operationId":"accountElevenLabsVoicesRefresh","summary":"Refresh account ElevenLabs voices","description":"Replaces the account's mirrored ElevenLabs voice metadata from its active key. Repeating it is safe.","tags":["User"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"provider":{"type":"string","enum":["elevenlabs"]},"active_voice_count":{"type":"integer","minimum":0},"synced_at":{"type":"integer","minimum":0}},"required":["account_id","provider","active_voice_count","synced_at"],"additionalProperties":false}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/billing/checkout":{"post":{"operationId":"checkoutCreate","summary":"Create a Stripe Checkout session","description":"Creates one idempotent hosted Checkout session for an approved credit amount and owner account.","tags":["User"],"security":[{"oauth2":["write"]},{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","minLength":1,"maxLength":64},"amount":{"type":"string","enum":["eur20","eur100"]},"request_id":{"type":"string","minLength":1,"maxLength":64},"return_to":{"type":"string","minLength":1,"maxLength":2048}},"required":["account_id","amount","request_id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"checkout_url":{"type":"string","format":"uri"},"session_id":{"type":"string","minLength":1}},"required":["checkout_url","session_id"],"additionalProperties":false}}}},"400":{"description":"The request or return target is malformed or unsafe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"The request id conflicts with an earlier attempt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"Stripe Checkout is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/billing/checkout/{sessionId}":{"get":{"operationId":"checkoutGet","summary":"Read what became of a Checkout session","description":"Reads this service own record of one owner-authorized Checkout session and whether its verified webhook has credited the account.","tags":["User"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"sessionId path parameter"},"required":true,"description":"sessionId path parameter","name":"sessionId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"session_id":{"type":"string","minLength":1},"account_id":{"type":"string","minLength":1},"amount":{"type":"string","enum":["eur20","eur100"]},"credits":{"type":"integer","exclusiveMinimum":0},"currency":{"type":"string","enum":["eur"]},"net_amount":{"type":["integer","null"],"minimum":0},"tax_amount":{"type":["integer","null"],"minimum":0},"total_amount":{"type":["integer","null"],"minimum":0},"status":{"type":"string","enum":["pending","credited"]},"credited_at":{"type":["string","null"]},"balance_credits":{"type":"integer"}},"required":["session_id","account_id","amount","credits","currency","net_amount","tax_amount","total_amount","status","credited_at","balance_credits"],"additionalProperties":false}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The session belongs to an account you do not own","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No such session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/billing/mpp/purchases":{"post":{"operationId":"creditPurchaseCreate","summary":"Quote a credit purchase for MPP","description":"Creates an owner-authorized credit purchase with a Stripe tax quote and no payment confirmation.","tags":["User"],"security":[{"oauth2":["write"]},{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","minLength":1,"maxLength":64},"product":{"type":"string","enum":["eur20","eur100"]},"request_id":{"type":"string","minLength":1,"maxLength":64},"billing":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"email":{"type":"string","format":"email"},"address":{"type":"object","properties":{"line1":{"type":"string","minLength":1,"maxLength":200},"line2":{"type":"string","maxLength":200},"city":{"type":"string","minLength":1,"maxLength":100},"postal_code":{"type":"string","minLength":1,"maxLength":30},"state":{"type":"string","maxLength":100},"country":{"type":"string","pattern":"^[A-Z]{2}$"}},"required":["line1","city","postal_code","country"],"additionalProperties":false},"tax_id":{"type":"object","properties":{"type":{"type":"string","enum":["eu_vat"]},"value":{"type":"string","minLength":1,"maxLength":40}},"required":["type","value"],"additionalProperties":false}},"required":["name","email","address"],"additionalProperties":false,"description":"Required only to establish the account billing identity; existing details are managed in Stripe."}},"required":["account_id","product","request_id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"purchase_id":{"type":"string"},"account_id":{"type":"string"},"product":{"type":"string","enum":["eur20","eur100"]},"credits":{"type":"integer","exclusiveMinimum":0},"currency":{"type":"string","enum":["eur"]},"net_amount":{"type":"integer","exclusiveMinimum":0},"tax_amount":{"type":"integer","minimum":0},"total_amount":{"type":"integer","exclusiveMinimum":0},"expires_at":{"type":"string"},"status":{"type":"string","enum":["awaiting_payment","credited"]},"payment_url":{"type":"string","format":"uri"},"invoice_url":{"type":["string","null"],"format":"uri"},"purchase_notice":{"type":"string"},"balance_credits":{"type":"integer"}},"required":["purchase_id","account_id","product","credits","currency","net_amount","tax_amount","total_amount","expires_at","status","payment_url","invoice_url","purchase_notice","balance_credits"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/billing/mpp/purchases/{purchaseId}":{"get":{"operationId":"creditPurchaseGet","summary":"Read a credit purchase","description":"Reads the stored credit-purchase status and its authorized Stripe-hosted invoice link.","tags":["User"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"purchaseId path parameter"},"required":true,"description":"purchaseId path parameter","name":"purchaseId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"purchase_id":{"type":"string"},"account_id":{"type":"string"},"product":{"type":"string","enum":["eur20","eur100"]},"credits":{"type":"integer","exclusiveMinimum":0},"currency":{"type":"string","enum":["eur"]},"net_amount":{"type":"integer","exclusiveMinimum":0},"tax_amount":{"type":"integer","minimum":0},"total_amount":{"type":"integer","exclusiveMinimum":0},"expires_at":{"type":"string"},"status":{"type":"string","enum":["awaiting_payment","credited"]},"payment_url":{"type":"string","format":"uri"},"invoice_url":{"type":["string","null"],"format":"uri"},"purchase_notice":{"type":"string"},"balance_credits":{"type":"integer"}},"required":["purchase_id","account_id","product","credits","currency","net_amount","tax_amount","total_amount","expires_at","status","payment_url","invoice_url","purchase_notice","balance_credits"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces":{"get":{"operationId":"spacesList","summary":"List spaces","description":"Lists active spaces available through an account membership or direct grant.","tags":["Space"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":120},"required":false,"name":"query","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50},"required":false,"name":"limit","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"spaces":{"type":"array","items":{"type":"object","properties":{"space_id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"account_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"role":{"type":"string","enum":["owner","editor","viewer"]},"name":{"type":"string"},"asset_count":{"type":"integer","minimum":0},"is_public":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"web_url":{"type":"string","format":"uri"}},"required":["space_id","account_id","role","name","asset_count","is_public","created_at","updated_at","web_url"]}}},"required":["spaces"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"spaceCreate","summary":"Create space","description":"Creates one account-scoped space. Its human-readable id is never auto-suffixed.","tags":["Space"],"security":[{"oauth2":["write"]},{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1,"maxLength":120},"space_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"}},"required":["name"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"space":{"type":"object","properties":{"space_id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"account_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"role":{"type":"string","enum":["owner","editor","viewer"]},"name":{"type":"string"},"asset_count":{"type":"integer","minimum":0},"is_public":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"web_url":{"type":"string","format":"uri"}},"required":["space_id","account_id","role","name","asset_count","is_public","created_at","updated_at","web_url"]}},"required":["space"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"The local space id is already reserved in this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/spaces/{accountId}/{spaceId}/access":{"get":{"operationId":"spaceAccess","summary":"Read canvas access","description":"Reads only the role and visibility a canvas needs before its socket connects.","tags":["Space"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["owner","editor","viewer"]},"is_public":{"type":"boolean"}},"required":["role","is_public"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}":{"get":{"operationId":"spaceGet","summary":"Get space","description":"Reads one authorized space and its current Durable Object snapshot.","tags":["Space"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","enum":["true","false"],"default":false},"required":false,"name":"starred_only","in":"query"},{"schema":{"type":"string","enum":["result","canvas"],"default":"result"},"required":false,"name":"media_window","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"space":{"type":"object","properties":{"space_id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"account_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"role":{"type":"string","enum":["owner","editor","viewer"]},"name":{"type":"string"},"asset_count":{"type":"integer","minimum":0},"is_public":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"web_url":{"type":"string","format":"uri"}},"required":["space_id","account_id","role","name","asset_count","is_public","created_at","updated_at","web_url"]},"assets":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string"},"space_id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"kind":{"type":"string","enum":["image","video","audio"]},"name":{"type":"string"},"status":{"type":"string","enum":["queued","generating","uploading","ready","failed"]},"note":{"type":["string","null"]},"traits":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"starred":{"type":"boolean"},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]},"media":{"type":["object","null"],"properties":{"mime":{"type":"string"},"size_bytes":{"type":"integer","minimum":0},"width":{"type":["integer","null"],"minimum":0},"height":{"type":["integer","null"],"minimum":0},"duration_ms":{"type":["integer","null"],"minimum":0}},"required":["mime","size_bytes","width","height","duration_ms"]},"media_url":{"type":["string","null"],"format":"uri"},"thumb_url":{"type":["string","null"],"format":"uri"},"recipe":{"type":["object","null"],"properties":{"origin":{"type":"string","enum":["generated","declared"]},"provider":{"type":"string"},"provider_model":{"type":["string","null"]},"provider_model_kind":{"type":["string","null"],"enum":["snapshot","alias",null]},"model":{"type":"string"},"terms":{"type":["string","null"]},"billing":{"type":["string","null"],"enum":["platform","own_key",null]},"prompt":{"type":"string"},"params":{"type":"object","additionalProperties":{}},"seed":{"type":["integer","null"]},"from_asset_id":{"type":["string","null"]},"provider_request_id":{"type":["string","null"]},"external_run_id":{"type":["string","null"]},"references":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string"},"slot":{"type":"string"},"order":{"type":"integer"},"unresolved":{"type":"string","enum":["deleted","filtered"]}},"required":["asset_id","slot","order"]}}},"required":["origin","provider","model","prompt","params","references"]},"word_timings":{"type":["object","null"],"properties":{"schema_version":{"type":"number","enum":[1]},"provenance":{"type":"string","enum":["generated_alignment","forced_alignment"]},"size_bytes":{"type":"integer","minimum":1,"maximum":2097152}},"required":["schema_version","provenance","size_bytes"],"additionalProperties":false},"audio_alignment":{"type":["object","null"],"properties":{"alignment_job_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed"]},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"]}},"required":["alignment_job_id","status","error"],"additionalProperties":false},"credits":{"type":"object","properties":{"estimated":{"type":"integer","minimum":0},"charged":{"type":["integer","null"],"minimum":0}},"required":["estimated","charged"]},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"]},"renders_in":{"type":"string","enum":["browser"]},"created_by":{"type":"object","properties":{"kind":{"type":"string","enum":["user","agent"]},"label":{"type":["string","null"]}},"required":["kind","label"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"web_url":{"type":"string","format":"uri"}},"required":["asset_id","space_id","kind","name","status","note","traits","tags","starred","position","media","media_url","thumb_url","recipe","word_timings","audio_alignment","credits","error","created_by","created_at","updated_at","web_url"]}},"links":{"type":"array","items":{"type":"object","properties":{"link_id":{"type":"string"},"from_asset_id":{"type":"string"},"to_asset_id":{"type":"string"},"label":{"type":["string","null"]}},"required":["link_id","from_asset_id","to_asset_id","label"]}},"web_url":{"type":"string","format":"uri"}},"required":["space","assets","links","web_url"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"patch":{"operationId":"spaceVisibility","summary":"Set space visibility","description":"Sets whether one active space has an anonymous read-only snapshot. Account owners only.","tags":["Space"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"is_public":{"type":"boolean"}},"required":["is_public"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"space":{"type":"object","properties":{"space_id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"account_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"role":{"type":"string","enum":["owner","editor","viewer"]},"name":{"type":"string"},"asset_count":{"type":"integer","minimum":0},"is_public":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"web_url":{"type":"string","format":"uri"}},"required":["space_id","account_id","role","name","asset_count","is_public","created_at","updated_at","web_url"]}},"required":["space"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"operationId":"spaceDelete","summary":"Delete space","description":"Soft-deletes one space. Only an active account owner may do this.","tags":["Space"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"space_id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"web_url":{"type":"string","format":"uri"}},"required":["ok","space_id","web_url"]}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}/export.json":{"get":{"operationId":"spaceExport","summary":"Export space","description":"Returns the canonical metadata-only v1 export from one authorized space snapshot.","tags":["Space"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","enum":["true","false"],"default":false},"required":false,"name":"starred_only","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"export_version":{"type":"number","enum":[1]},"space":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"account_id":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1,"maxLength":120},"is_public":{"type":"boolean"},"exported_at":{"type":"string","pattern":"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"},"url_expires_at":{"type":["string","null"],"pattern":"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"},"starred_only":{"type":"boolean"},"asset_count":{"type":"integer","minimum":0,"maximum":500},"web_url":{"type":"string","maxLength":4096,"format":"uri"}},"required":["id","account_id","name","is_public","exported_at","url_expires_at","starred_only","asset_count","web_url"],"additionalProperties":false},"assets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":64},"kind":{"type":"string","enum":["image","video","audio"]},"name":{"type":"string","minLength":1,"maxLength":120},"mime":{"type":"string","minLength":1,"maxLength":255},"size_bytes":{"type":"integer","exclusiveMinimum":0},"media_url":{"type":"string","maxLength":4096,"format":"uri"},"thumb_url":{"type":["string","null"],"maxLength":4096,"format":"uri"},"word_timings":{"type":["object","null"],"properties":{"schema_version":{"type":"number","enum":[1]},"provenance":{"type":"string","enum":["generated_alignment","forced_alignment"]},"size_bytes":{"type":"integer","minimum":1,"maximum":2097152},"json_url":{"type":"string","maxLength":4096,"format":"uri"}},"required":["schema_version","provenance","size_bytes","json_url"],"additionalProperties":false},"width":{"type":["integer","null"],"exclusiveMinimum":0},"height":{"type":["integer","null"],"exclusiveMinimum":0},"duration_ms":{"type":["integer","null"],"minimum":0},"starred":{"type":"boolean"},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":16},"note":{"type":["string","null"],"maxLength":4000},"traits":{"type":["string","null"],"maxLength":4000},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"],"additionalProperties":false},"credits":{"type":"object","properties":{"estimated":{"type":"integer","minimum":0},"charged":{"type":"integer","minimum":0}},"required":["estimated","charged"],"additionalProperties":false},"created_by":{"type":"object","properties":{"kind":{"type":"string","enum":["user","agent"]},"label":{"type":["string","null"],"maxLength":120}},"required":["kind","label"],"additionalProperties":false},"created_at":{"type":"string","pattern":"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"},"recipe":{"type":["object","null"],"properties":{"origin":{"type":"string","enum":["generated","declared"]},"provider":{"type":"string","minLength":1,"maxLength":200},"provider_model":{"type":["string","null"],"minLength":1,"maxLength":200},"provider_model_kind":{"type":["string","null"],"enum":["snapshot","alias",null]},"model":{"type":"string","minLength":1,"maxLength":200},"terms":{"type":["string","null"],"minLength":1,"maxLength":200},"billing":{"type":["string","null"],"enum":["platform","own_key",null]},"prompt":{"type":"string","maxLength":8000},"params":{"type":"object","additionalProperties":{}},"references":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1,"maxLength":64},"slot":{"type":"string","minLength":1,"maxLength":64},"order":{"type":"integer","minimum":0},"unresolved":{"type":"string","enum":["deleted","filtered"]}},"required":["asset_id","slot","order"],"additionalProperties":false},"maxItems":64},"seed":{"type":["integer","null"]},"from_asset_id":{"type":["string","null"],"minLength":1,"maxLength":64},"provider_request_id":{"type":["string","null"],"maxLength":200},"external_run_id":{"type":["string","null"],"maxLength":200}},"required":["origin","provider","provider_model","provider_model_kind","model","terms","billing","prompt","params","references","seed","from_asset_id","provider_request_id","external_run_id"],"additionalProperties":false},"web_url":{"type":"string","maxLength":4096,"format":"uri"}},"required":["id","kind","name","mime","size_bytes","media_url","thumb_url","word_timings","width","height","duration_ms","starred","tags","note","traits","position","credits","created_by","created_at","recipe","web_url"],"additionalProperties":false},"maxItems":500},"links":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":64},"from_asset_id":{"type":"string","minLength":1,"maxLength":64},"to_asset_id":{"type":"string","minLength":1,"maxLength":64},"label":{"type":["string","null"],"maxLength":80},"from_unresolved":{"type":"string","enum":["deleted","filtered"]},"to_unresolved":{"type":"string","enum":["deleted","filtered"]}},"required":["id","from_asset_id","to_asset_id","label"],"additionalProperties":false},"maxItems":2000}},"required":["export_version","space","assets","links"],"additionalProperties":false}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"The selected export exceeds a v1 admission budget","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/credits/estimate":{"post":{"operationId":"creditsEstimate","summary":"Estimate generation credits","description":"Validates and prices one generation request without reserving credits.","tags":["Asset"],"security":[{"oauth2":["read"]},{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"space_id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"kind":{"type":"string","enum":["image","video","audio"]},"model":{"type":"string","minLength":1},"prompt":{"type":"string","maxLength":8000,"default":""},"references":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1,"maxLength":64},"slot":{"type":"string","minLength":1,"maxLength":64},"order":{"type":"integer","minimum":0}},"required":["asset_id","slot"],"additionalProperties":false},"maxItems":64,"default":[]},"params":{"type":"object","additionalProperties":{},"default":{}},"count":{"type":"integer","minimum":1,"maximum":8,"default":1},"from_asset_id":{"type":"string","minLength":1,"maxLength":64},"recipe_mode":{"type":"string","enum":["current","exact"],"default":"current"}},"required":["kind","model"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"credits":{"type":"integer","minimum":0},"per_asset_credits":{"type":"integer","minimum":0},"terms":{"type":"string"},"balance_credits":{"type":"integer"},"balance_after_credits":{"type":"integer"},"topup_url":{"type":"string","format":"uri"}},"required":["credits","per_asset_credits","terms","balance_credits","balance_after_credits"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"parameters":[{"$ref":"#/components/parameters/ApiVersion"}]}},"/api/spaces/{accountId}/{spaceId}/assets":{"post":{"operationId":"assetCreate","summary":"Create assets","description":"Creates one to eight generations whose per-Asset holds are admitted together, optionally using an existing Asset Recipe with its current or recorded provider model.","tags":["Asset"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["image","video","audio"]},"model":{"type":"string","minLength":1},"prompt":{"type":"string","maxLength":8000,"default":""},"references":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1,"maxLength":64},"slot":{"type":"string","minLength":1,"maxLength":64},"order":{"type":"integer","minimum":0}},"required":["asset_id","slot"],"additionalProperties":false},"maxItems":64,"default":[]},"params":{"type":"object","additionalProperties":{},"default":{}},"count":{"type":"integer","minimum":1,"maximum":8,"default":1},"from_asset_id":{"type":"string","minLength":1,"maxLength":64},"recipe_mode":{"type":"string","enum":["current","exact"],"default":"current"},"name":{"type":"string","minLength":1,"maxLength":120},"seed":{"type":"integer"},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"],"additionalProperties":false},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":16,"default":[]},"note":{"type":"string","maxLength":4000},"request_id":{"type":"string","minLength":1,"maxLength":64}},"required":["kind","model"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"assets":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string"},"status":{"type":"string","enum":["queued","generating","ready"]},"estimated_credits":{"type":"integer","minimum":0},"terms":{"type":"string"},"next_poll_seconds":{"type":["integer","null"]},"renders_in":{"type":"string","enum":["browser"]},"task_id":{"type":"string"},"web_url":{"type":"string","format":"uri"}},"required":["asset_id","status","estimated_credits","terms","web_url"]},"minItems":1,"maxItems":8},"estimated_credits":{"type":"integer","minimum":0},"balance_after_credits":{"type":"integer"},"space_web_url":{"type":"string","format":"uri"},"idempotent_replay":{"type":"boolean"}},"required":["assets","estimated_credits","balance_after_credits","space_web_url"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"402":{"description":"The balance cannot cover the guarded holds","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"The generation worker could not accept the workflow","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}/uploads":{"post":{"operationId":"assetUpload","summary":"Reserve an asset upload","description":"Creates one uploading asset and returns a short-lived one-use direct PUT URL.","tags":["Asset"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["image","video","audio"]},"filename":{"type":"string","minLength":1,"maxLength":255},"mime":{"type":"string","minLength":1,"maxLength":100},"size_bytes":{"type":"integer","minimum":1,"maximum":2147483648},"name":{"type":"string","minLength":1,"maxLength":120},"recipe":{"type":"object","properties":{"provider":{"type":"string","enum":["external"]},"model":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[a-z0-9]+(?:[-_][a-z0-9]+)*$"},"prompt":{"type":"string","maxLength":8000,"default":""},"params":{"type":"object","additionalProperties":{},"default":{}},"references":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1,"maxLength":64},"slot":{"type":"string","minLength":1,"maxLength":64},"order":{"type":"integer","minimum":0}},"required":["asset_id","slot","order"],"additionalProperties":false},"maxItems":64,"default":[]},"external_run_id":{"type":["string","null"],"maxLength":200}},"required":["provider","model"],"additionalProperties":false},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"],"additionalProperties":false},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":16,"default":[]},"request_id":{"type":"string","minLength":1,"maxLength":64}},"required":["kind","filename","mime","size_bytes"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"asset_id":{"type":"string"},"upload_url":{"type":"string","format":"uri"},"method":{"type":"string","enum":["PUT"]},"headers":{"type":"object","additionalProperties":{"type":"string"}},"expires_at":{"type":"string","format":"date-time"},"next_poll_seconds":{"type":"integer"},"web_url":{"type":"string","format":"uri"},"idempotent_replay":{"type":"boolean"}},"required":["asset_id","upload_url","method","headers","expires_at","next_poll_seconds","web_url"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}/assets/{assetId}":{"get":{"operationId":"assetGet","summary":"Get asset","description":"Reads one asset, optionally waiting for its generation status to change.","tags":["Asset"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","description":"assetId path parameter"},"required":true,"description":"assetId path parameter","name":"assetId","in":"path"},{"schema":{"type":["integer","null"],"minimum":0,"maximum":60,"default":0},"required":false,"name":"wait_seconds","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"asset":{"type":"object","properties":{"asset_id":{"type":"string"},"space_id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"kind":{"type":"string","enum":["image","video","audio"]},"name":{"type":"string"},"status":{"type":"string","enum":["queued","generating","uploading","ready","failed"]},"note":{"type":["string","null"]},"traits":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"starred":{"type":"boolean"},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]},"media":{"type":["object","null"],"properties":{"mime":{"type":"string"},"size_bytes":{"type":"integer","minimum":0},"width":{"type":["integer","null"],"minimum":0},"height":{"type":["integer","null"],"minimum":0},"duration_ms":{"type":["integer","null"],"minimum":0}},"required":["mime","size_bytes","width","height","duration_ms"]},"media_url":{"type":["string","null"],"format":"uri"},"thumb_url":{"type":["string","null"],"format":"uri"},"recipe":{"type":["object","null"],"properties":{"origin":{"type":"string","enum":["generated","declared"]},"provider":{"type":"string"},"provider_model":{"type":["string","null"]},"provider_model_kind":{"type":["string","null"],"enum":["snapshot","alias",null]},"model":{"type":"string"},"terms":{"type":["string","null"]},"billing":{"type":["string","null"],"enum":["platform","own_key",null]},"prompt":{"type":"string"},"params":{"type":"object","additionalProperties":{}},"seed":{"type":["integer","null"]},"from_asset_id":{"type":["string","null"]},"provider_request_id":{"type":["string","null"]},"external_run_id":{"type":["string","null"]},"references":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string"},"slot":{"type":"string"},"order":{"type":"integer"},"unresolved":{"type":"string","enum":["deleted","filtered"]}},"required":["asset_id","slot","order"]}}},"required":["origin","provider","model","prompt","params","references"]},"word_timings":{"type":["object","null"],"properties":{"schema_version":{"type":"number","enum":[1]},"provenance":{"type":"string","enum":["generated_alignment","forced_alignment"]},"size_bytes":{"type":"integer","minimum":1,"maximum":2097152}},"required":["schema_version","provenance","size_bytes"],"additionalProperties":false},"audio_alignment":{"type":["object","null"],"properties":{"alignment_job_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed"]},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"]}},"required":["alignment_job_id","status","error"],"additionalProperties":false},"credits":{"type":"object","properties":{"estimated":{"type":"integer","minimum":0},"charged":{"type":["integer","null"],"minimum":0}},"required":["estimated","charged"]},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"]},"renders_in":{"type":"string","enum":["browser"]},"created_by":{"type":"object","properties":{"kind":{"type":"string","enum":["user","agent"]},"label":{"type":["string","null"]}},"required":["kind","label"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"web_url":{"type":"string","format":"uri"}},"required":["asset_id","space_id","kind","name","status","note","traits","tags","starred","position","media","media_url","thumb_url","recipe","word_timings","audio_alignment","credits","error","created_by","created_at","updated_at","web_url"]},"next_poll_seconds":{"type":["integer","null"]},"web_url":{"type":"string","format":"uri"}},"required":["asset","web_url"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"patch":{"operationId":"assetUpdate","summary":"Update asset","description":"Updates editable metadata, position, or the declared recipe of an authorized asset.","tags":["Asset"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","description":"assetId path parameter"},"required":true,"description":"assetId path parameter","name":"assetId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"note":{"type":["string","null"],"maxLength":4000},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":16},"traits":{"type":["string","null"],"maxLength":4000},"starred":{"type":"boolean"},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"],"additionalProperties":false},"recipe":{"type":"object","properties":{"origin":{"type":"string","enum":["declared"]},"provider":{"type":"string","enum":["external"]},"model":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[a-z0-9]+(?:[-_][a-z0-9]+)*$"},"terms":{"type":"null"},"billing":{"type":"null"},"prompt":{"type":"string","maxLength":8000},"params":{"type":"object","additionalProperties":{}},"references":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1,"maxLength":64},"slot":{"type":"string","minLength":1,"maxLength":64},"order":{"type":"integer","minimum":0}},"required":["asset_id","slot","order"],"additionalProperties":false},"maxItems":64},"seed":{"type":["integer","null"]},"from_asset_id":{"type":["string","null"],"minLength":1,"maxLength":64},"provider_request_id":{"type":"null"},"external_run_id":{"type":["string","null"],"maxLength":200}},"required":["origin","provider","model","prompt","params","references"],"additionalProperties":false}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"asset":{"type":"object","properties":{"asset_id":{"type":"string"},"space_id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"kind":{"type":"string","enum":["image","video","audio"]},"name":{"type":"string"},"status":{"type":"string","enum":["queued","generating","uploading","ready","failed"]},"note":{"type":["string","null"]},"traits":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"starred":{"type":"boolean"},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]},"media":{"type":["object","null"],"properties":{"mime":{"type":"string"},"size_bytes":{"type":"integer","minimum":0},"width":{"type":["integer","null"],"minimum":0},"height":{"type":["integer","null"],"minimum":0},"duration_ms":{"type":["integer","null"],"minimum":0}},"required":["mime","size_bytes","width","height","duration_ms"]},"media_url":{"type":["string","null"],"format":"uri"},"thumb_url":{"type":["string","null"],"format":"uri"},"recipe":{"type":["object","null"],"properties":{"origin":{"type":"string","enum":["generated","declared"]},"provider":{"type":"string"},"provider_model":{"type":["string","null"]},"provider_model_kind":{"type":["string","null"],"enum":["snapshot","alias",null]},"model":{"type":"string"},"terms":{"type":["string","null"]},"billing":{"type":["string","null"],"enum":["platform","own_key",null]},"prompt":{"type":"string"},"params":{"type":"object","additionalProperties":{}},"seed":{"type":["integer","null"]},"from_asset_id":{"type":["string","null"]},"provider_request_id":{"type":["string","null"]},"external_run_id":{"type":["string","null"]},"references":{"type":"array","items":{"type":"object","properties":{"asset_id":{"type":"string"},"slot":{"type":"string"},"order":{"type":"integer"},"unresolved":{"type":"string","enum":["deleted","filtered"]}},"required":["asset_id","slot","order"]}}},"required":["origin","provider","model","prompt","params","references"]},"word_timings":{"type":["object","null"],"properties":{"schema_version":{"type":"number","enum":[1]},"provenance":{"type":"string","enum":["generated_alignment","forced_alignment"]},"size_bytes":{"type":"integer","minimum":1,"maximum":2097152}},"required":["schema_version","provenance","size_bytes"],"additionalProperties":false},"audio_alignment":{"type":["object","null"],"properties":{"alignment_job_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed"]},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"]}},"required":["alignment_job_id","status","error"],"additionalProperties":false},"credits":{"type":"object","properties":{"estimated":{"type":"integer","minimum":0},"charged":{"type":["integer","null"],"minimum":0}},"required":["estimated","charged"]},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"]},"renders_in":{"type":"string","enum":["browser"]},"created_by":{"type":"object","properties":{"kind":{"type":"string","enum":["user","agent"]},"label":{"type":["string","null"]}},"required":["kind","label"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"web_url":{"type":"string","format":"uri"}},"required":["asset_id","space_id","kind","name","status","note","traits","tags","starred","position","media","media_url","thumb_url","recipe","word_timings","audio_alignment","credits","error","created_by","created_at","updated_at","web_url"]}},"required":["asset"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"operationId":"assetDelete","summary":"Delete asset","description":"Idempotently soft-deletes one asset while preserving its media, recipe, and credit trail.","tags":["Asset"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","description":"assetId path parameter"},"required":true,"description":"assetId path parameter","name":"assetId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"asset_id":{"type":"string"}},"required":["ok","asset_id"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}/assets/{assetId}/describe":{"post":{"operationId":"assetDescribe","summary":"Describe asset traits","description":"Charges the space account once and writes fixed visual traits for a ready image or video's poster.","tags":["Asset"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","description":"assetId path parameter"},"required":true,"description":"assetId path parameter","name":"assetId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string","minLength":1,"maxLength":64}},"required":["request_id"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"asset_id":{"type":"string"},"traits":{"type":"string"},"credits_charged":{"type":"integer","exclusiveMinimum":0},"balance_after_credits":{"type":"integer","minimum":0},"space_seq":{"type":["integer","null"],"minimum":0},"web_url":{"type":"string","format":"uri"},"idempotent_replay":{"type":"boolean"}},"required":["asset_id","traits","credits_charged","balance_after_credits","web_url"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"402":{"description":"The balance cannot cover Describe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"The idempotent request is still being completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"The media is unreadable or blocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"Describe is unavailable or pending recovery","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}/assets/{assetId}/audio-alignments":{"post":{"operationId":"audioAlignmentStart","summary":"Align audio","description":"Starts durable forced alignment for an unchanged ready audio asset.","tags":["Asset"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","description":"assetId path parameter"},"required":true,"description":"assetId path parameter","name":"assetId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":675000},"request_id":{"type":"string","minLength":1,"maxLength":64}},"required":["request_id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"alignment_job":{"type":"object","properties":{"alignment_job_id":{"type":"string"},"asset_id":{"type":"string"},"request_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed"]},"terms":{"type":"string"},"billing":{"type":"string","enum":["platform","own_key"]},"estimated_credits":{"type":"integer","minimum":1},"charged_credits":{"type":["integer","null"],"minimum":0},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"}},"required":["alignment_job_id","asset_id","request_id","status","terms","billing","estimated_credits","charged_credits","error","created_at","updated_at","completed_at"],"additionalProperties":false},"word_timings":{"type":["object","null"],"properties":{"schema_version":{"type":"number","enum":[1]},"provenance":{"type":"string","enum":["generated_alignment","forced_alignment"]},"size_bytes":{"type":"integer","minimum":1,"maximum":2097152}},"required":["schema_version","provenance","size_bytes"],"additionalProperties":false},"balance_after_credits":{"type":"integer"},"next_poll_seconds":{"type":["integer","null"]},"web_url":{"type":"string","format":"uri"},"idempotent_replay":{"type":"boolean"}},"required":["alignment_job","word_timings","balance_after_credits","next_poll_seconds","web_url"],"additionalProperties":false}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"402":{"description":"The balance cannot cover the alignment hold","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Another alignment owns this asset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"Alignment admission is unavailable or reconciling","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}/audio-alignments/{alignmentJobId}":{"get":{"operationId":"audioAlignmentGet","summary":"Get audio alignment job","description":"Reads or waits on one durable alignment job without returning the timing document.","tags":["Asset"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","description":"alignmentJobId path parameter"},"required":true,"description":"alignmentJobId path parameter","name":"alignmentJobId","in":"path"},{"schema":{"type":["integer","null"],"minimum":0,"maximum":60,"default":0},"required":false,"name":"wait_seconds","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"alignment_job":{"type":"object","properties":{"alignment_job_id":{"type":"string"},"asset_id":{"type":"string"},"request_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed"]},"terms":{"type":"string"},"billing":{"type":"string","enum":["platform","own_key"]},"estimated_credits":{"type":"integer","minimum":1},"charged_credits":{"type":["integer","null"],"minimum":0},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"}},"required":["alignment_job_id","asset_id","request_id","status","terms","billing","estimated_credits","charged_credits","error","created_at","updated_at","completed_at"],"additionalProperties":false},"word_timings":{"type":["object","null"],"properties":{"schema_version":{"type":"number","enum":[1]},"provenance":{"type":"string","enum":["generated_alignment","forced_alignment"]},"size_bytes":{"type":"integer","minimum":1,"maximum":2097152}},"required":["schema_version","provenance","size_bytes"],"additionalProperties":false},"next_poll_seconds":{"type":["integer","null"]}},"required":["alignment_job","word_timings","next_poll_seconds"],"additionalProperties":false}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}/assets/{assetId}/word-timings":{"get":{"operationId":"audioWordTimingsGet","summary":"Get audio word timings","description":"Streams the active canonical timing attachment for a ready audio asset.","tags":["Asset"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","description":"assetId path parameter"},"required":true,"description":"assetId path parameter","name":"assetId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"schema_version":{"type":"number","enum":[1]},"text":{"type":"string","minLength":1},"words":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string","minLength":1},"start_ms":{"type":"integer","minimum":0},"end_ms":{"type":"integer","minimum":0},"start_char":{"type":"integer","minimum":0},"end_char":{"type":"integer","exclusiveMinimum":0},"loss":{"type":"number","minimum":0}},"required":["text","start_ms","end_ms","start_char","end_char"],"additionalProperties":false},"minItems":1},"provenance":{"type":"object","properties":{"method":{"type":"string","enum":["generated_alignment","forced_alignment"]},"provider":{"type":"string"},"provider_request_id":{"type":"string"}},"required":["method"],"additionalProperties":false},"quality":{"type":"object","properties":{"loss":{"type":"number","minimum":0}},"additionalProperties":false}},"required":["schema_version","text","words","provenance"],"additionalProperties":false}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}/assets/{assetId}/word-timings/inspect":{"get":{"operationId":"audioWordTimingsInspect","summary":"Inspect audio timings","description":"Returns the active timing document and optionally waits on one alignment job.","tags":["Asset"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"schema":{"type":"string","description":"assetId path parameter"},"required":true,"description":"assetId path parameter","name":"assetId","in":"path"},{"schema":{"type":"string"},"required":false,"name":"alignment_job_id","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"maximum":60,"default":0},"required":false,"name":"wait_seconds","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"asset_id":{"type":"string"},"word_timings":{"type":["object","null"],"properties":{"schema_version":{"type":"number","enum":[1]},"text":{"type":"string","minLength":1},"words":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string","minLength":1},"start_ms":{"type":"integer","minimum":0},"end_ms":{"type":"integer","minimum":0},"start_char":{"type":"integer","minimum":0},"end_char":{"type":"integer","exclusiveMinimum":0},"loss":{"type":"number","minimum":0}},"required":["text","start_ms","end_ms","start_char","end_char"],"additionalProperties":false},"minItems":1},"provenance":{"type":"object","properties":{"method":{"type":"string","enum":["generated_alignment","forced_alignment"]},"provider":{"type":"string"},"provider_request_id":{"type":"string"}},"required":["method"],"additionalProperties":false},"quality":{"type":"object","properties":{"loss":{"type":"number","minimum":0}},"additionalProperties":false}},"required":["schema_version","text","words","provenance"],"additionalProperties":false},"alignment_job":{"type":["object","null"],"properties":{"alignment_job_id":{"type":"string"},"asset_id":{"type":"string"},"request_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed"]},"terms":{"type":"string"},"billing":{"type":"string","enum":["platform","own_key"]},"estimated_credits":{"type":"integer","minimum":1},"charged_credits":{"type":["integer","null"],"minimum":0},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"}},"required":["code","message","retryable"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"}},"required":["alignment_job_id","asset_id","request_id","status","terms","billing","estimated_credits","charged_credits","error","created_at","updated_at","completed_at"],"additionalProperties":false},"next_poll_seconds":{"type":["integer","null"]},"web_url":{"type":"string","format":"uri"}},"required":["asset_id","word_timings","alignment_job","next_poll_seconds","web_url"],"additionalProperties":false}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/spaces/{accountId}/{spaceId}/links":{"post":{"operationId":"linkCreate","summary":"Link assets","description":"Creates one manual labeled edge between two active assets in the same authorized space.","tags":["Link"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"from_asset_id":{"type":"string","minLength":1,"maxLength":64},"to_asset_id":{"type":"string","minLength":1,"maxLength":64},"label":{"type":"string","maxLength":80}},"required":["from_asset_id","to_asset_id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"link":{"type":"object","properties":{"link_id":{"type":"string"},"from_asset_id":{"type":"string"},"to_asset_id":{"type":"string"},"label":{"type":["string","null"]}},"required":["link_id","from_asset_id","to_asset_id","label"]}},"required":["link"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"operationId":"linkDelete","summary":"Unlink assets","description":"Idempotently soft-deletes one manual link by id or by its active endpoint pair.","tags":["Link"],"security":[{"oauth2":["write"]},{"session":[]}],"parameters":[{"schema":{"type":"string","description":"accountId path parameter"},"required":true,"description":"accountId path parameter","name":"accountId","in":"path"},{"schema":{"type":"string","description":"spaceId path parameter"},"required":true,"description":"spaceId path parameter","name":"spaceId","in":"path"},{"$ref":"#/components/parameters/ApiVersion"}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"from_asset_id":{"type":"string","minLength":1,"maxLength":64},"to_asset_id":{"type":"string","minLength":1,"maxLength":64},"label":{"type":"string","maxLength":80}},"required":["from_asset_id","to_asset_id"],"additionalProperties":false},{"type":"object","properties":{"link_id":{"type":"string","minLength":1,"maxLength":64}},"required":["link_id"],"additionalProperties":false}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/models":{"get":{"operationId":"modelsList","summary":"List models","description":"Lists the model catalog, optionally filtered by media kind or model family and scoped to an authorized space billing account.","tags":["Models"],"security":[{"oauth2":["read"]},{"session":[]}],"parameters":[{"schema":{"type":"string","enum":["image","video","audio"]},"required":false,"name":"kind","in":"query"},{"schema":{"type":"string","enum":["provider","internal","browser"]},"required":false,"name":"family","in":"query"},{"schema":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*\\/[a-z0-9]+(?:-[a-z0-9]+)*$"},"required":false,"name":"space_id","in":"query"},{"$ref":"#/components/parameters/ApiVersion"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"credit_eur":{"type":"number","exclusiveMinimum":0},"models":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"terms":{"type":"string"},"kind":{"type":"string","enum":["image","video","audio"]},"family":{"type":"string","enum":["provider","internal","browser"]},"provider":{"type":"string"},"provider_model":{"type":"string"},"provider_model_kind":{"type":"string","enum":["snapshot","alias"]},"label":{"type":"string"},"description":{"type":"string"},"default_for_kind":{"type":"boolean"},"availability":{"type":"string","enum":["available","preview","unavailable"]},"typical_seconds":{"type":"number","minimum":0},"params_schema":{"type":"object","additionalProperties":{}},"reference_slots":{"type":"array","items":{"type":"object","properties":{"slot":{"type":"string"},"kinds":{"type":"array","items":{"type":"string","enum":["image","video","audio"]}},"min":{"type":"integer","minimum":0},"max":{"type":"integer","minimum":0},"order":{"type":"string"},"exclusive_with":{"type":"array","items":{"type":"string"}},"requires":{"type":"array","items":{"type":"string"}}},"required":["slot","kinds","min","max"]}},"output":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"}]}},"price":{"type":"object","properties":{"unit":{"type":"string","enum":["image","second","minute","track","none"]},"credits":{"type":"number","minimum":0},"rules":{"type":"array","items":{"type":"object","properties":{"when":{"type":"object","additionalProperties":{"type":"string"}},"credits":{"type":"number","minimum":0}},"required":["when","credits"]}},"minimum_credits":{"type":"number","minimum":0},"until":{"type":["string","null"],"format":"date-time"},"after":{"type":["object","null"],"properties":{"credits":{"type":"number","minimum":0},"rules":{"type":"array","items":{"type":"object","properties":{"when":{"type":"object","additionalProperties":{"type":"string"}},"credits":{"type":"number","minimum":0}},"required":["when","credits"]}}},"required":["credits","rules"]}},"required":["unit","credits","rules","until","after"]},"error_codes":{"type":"array","items":{"type":"string"}},"hidden":{"type":"boolean"},"renders_in":{"type":"string","enum":["browser"]}},"required":["id","terms","kind","family","provider","provider_model","provider_model_kind","label","description","default_for_kind","availability","typical_seconds","params_schema","reference_slots","output","price","error_codes","hidden"]}},"actions":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","enum":["describe"]},"terms":{"type":"string"},"label":{"type":"string"},"tool":{"type":"string","enum":["describe_asset"]},"applies_to":{"type":"array","items":{"type":"string","enum":["image","video","audio"]}},"writes":{"type":"string","enum":["traits"]},"price":{"type":"object","properties":{"unit":{"type":"string","enum":["none"]},"credits":{"type":"number","minimum":0}},"required":["unit","credits"]}},"required":["id","terms","label","tool","applies_to","writes","price"]},{"type":"object","properties":{"id":{"type":"string","enum":["align_audio"]},"terms":{"type":"string"},"label":{"type":"string"},"tool":{"type":"string","enum":["align_audio"]},"applies_to":{"type":"array","prefixItems":[{"type":"string","enum":["audio"]}]},"writes":{"type":"string","enum":["word_timings"]},"price":{"type":"object","properties":{"unit":{"type":"string","enum":["minute"]},"credits":{"type":"number","exclusiveMinimum":0},"minimum_credits":{"type":"integer","exclusiveMinimum":0}},"required":["unit","credits","minimum_credits"]},"billing":{"type":"string","enum":["platform","own_key"]}},"required":["id","terms","label","tool","applies_to","writes","price"]}]}}},"required":["credit_eur","models","actions"]}}}},"400":{"description":"The request did not match the schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"No valid credentials. WWW-Authenticate names the protected resource metadata to start from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"The credentials are valid but not enough: the token lacks the scope, or the action needs a browser session rather than an app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limited. RateLimit names the policy; Retry-After says when to try again","headers":{"Retry-After":{"description":"Seconds until the bucket refills","schema":{"type":"integer"}},"RateLimit":{"description":"The policy, with nothing left in it","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}}},"webhooks":{}}