{"openapi":"3.1.0","info":{"title":"SchemaVaults Auth API","version":"0.46.3","description":"HTTP API of SchemaVaults Auth, SchemaVaults' own instance of @schemavaults/auth-server: authentication and OpenID Connect endpoints, account and organization management, client application and API server registrations, and platform administration.\n\nEvery operation is declared with @schemavaults/openapi-operations; this document and the /docs pages are generated from those declarations."},"servers":[{"url":"https://auth.schemavaults.com","description":"This auth server"}],"tags":[{"name":"Authentication","description":"Login, registration, e-mail verification and password reset for the auth server's own login pages and the client SDK."},{"name":"Multi-factor authentication","description":"TOTP and passkey (WebAuthn) enrollment, the login MFA challenge, and recovery codes."},{"name":"OpenID Connect / OAuth 2.0","description":"The standards-facing endpoints: discovery, authorization, token, userinfo, introspection, JWKS and dynamic client registration."},{"name":"Account","description":"The signed-in user's own profile, organization memberships and invitations."},{"name":"Client applications","description":"Client application (OAuth client) registrations and their configuration: domains, callback URLs, client secrets, service accounts, user authorization."},{"name":"API servers","description":"API server (resource server) registrations, their domains, JWKS access keys and app connections."},{"name":"Organizations","description":"Organizations, their members and invitations."},{"name":"Administration","description":"Platform administrator operations: users, invite codes, settings, branding, diagnostics."},{"name":"Resource servers","description":"Endpoints resource servers call on their own behalf with a JWKS access assertion: signing keys, allowed origins, membership lookups."},{"name":"Configuration","description":"Public deployment configuration (environment, branding, invite code policy)."},{"name":"Test environment","description":"Seeding and introspection endpoints used by the E2E suite. They respond 404 outside the `test` environment."}],"components":{"securitySchemes":{"schemavaults-refresh-token-cookie":{"type":"apiKey","in":"cookie","name":"refresh_token_<auth_server_app_id>","description":"Auth server session cookie.","x-schemavaults-title":"Auth server session (refresh token cookie)"},"schemavaults-access-token-cookie":{"type":"apiKey","in":"cookie","name":"access_token_<auth_server_app_id>","description":"First-party access token cookie set after login.","x-schemavaults-title":"Access token (cookie)"},"schemavaults-access-token":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Access token issued by the auth server for this API server.","x-schemavaults-title":"Access token (Bearer)","x-schemavaults-challenge":"Bearer realm=\"schemavaults\""},"schemavaults-jwks-access-assertion":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWKS access assertion signed by the API server's JWKS access key.","x-schemavaults-title":"JWKS access assertion (Bearer)","x-schemavaults-challenge":"Bearer realm=\"schemavaults-jwks-access\""},"schemavaults-client-app-refresh-token-cookie":{"type":"apiKey","in":"cookie","name":"refresh_token_<client_app_id>","description":"Client application refresh token cookie.","x-schemavaults-title":"Client app session (refresh token cookie)"}},"schemas":{"AuthenticateSuccessResult":{"anyOf":[{"$ref":"#/components/schemas/AuthenticatedResult"},{"$ref":"#/components/schemas/MfaRequiredResult"}],"description":"Discriminated on `kind`: `authenticated` or `mfa_required`."},"AuthenticatedResult":{"type":"object","properties":{"kind":{"type":"string","enum":["authenticated"]},"success":{"type":"boolean"},"message":{"type":"string"},"authorization_code":{"type":"string","minLength":43}},"required":["kind","success","message","authorization_code"],"additionalProperties":false,"description":"The user is authenticated: redeem `authorization_code` at `POST /api/oidc/token` (PKCE). The response also sets the auth server's HTTP-only session cookie."},"MfaRequiredResult":{"type":"object","properties":{"kind":{"type":"string","enum":["mfa_required"]},"success":{"type":"boolean"},"message":{"type":"string"},"challenge_id":{"type":"string","format":"uuid"},"expires_at":{"type":"integer","exclusiveMinimum":0},"available_factors":{"type":"array","items":{"type":"object","properties":{"factor_id":{"type":"string","format":"uuid"},"factor_type":{"type":"string","enum":["totp","webauthn"]},"last_used_at":{"type":["integer","null"],"exclusiveMinimum":0}},"required":["factor_id","factor_type","last_used_at"],"additionalProperties":false}},"recovery_codes_available":{"type":"boolean"}},"required":["kind","success","message","challenge_id","expires_at","available_factors","recovery_codes_available"],"additionalProperties":false,"description":"The password was accepted but the account has a verified second factor: complete the challenge at `POST /api/auth/mfa/verify` before `expires_at` (Unix epoch milliseconds). No session or authorization code is issued yet."},"AuthenticateBadRequest":{"anyOf":[{"$ref":"#/components/schemas/AuthenticateFailureResult"},{"$ref":"#/components/schemas/ZodIssuesResponse"},{"$ref":"#/components/schemas/ErrorResponse"}],"description":"An `AuthenticateFailureResult` (invalid JSON, `redirect_uri` problems, invite code problems, ...), the raw zod issues of a body that failed schema validation, or the plain `{ success: false, message }` envelope when the client IP could not be determined."},"AuthenticateFailureResult":{"type":"object","properties":{"kind":{"type":"string","enum":["failure"]},"success":{"type":"boolean"},"message":{"type":"string"}},"required":["kind","success","message"],"additionalProperties":false,"description":"The request was refused; `message` explains why."},"ZodIssuesResponse":{"type":"object","properties":{"issues":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"}},"required":["code","path","message"],"additionalProperties":{}}}},"required":["issues"],"additionalProperties":{},"description":"A serialized zod error: the request body did not match the endpoint's schema."},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"message":{"type":"string"},"error":{"anyOf":[{"type":"string"},{"type":"boolean"}]}},"required":["success","message"],"description":"Error envelope: `success` is false and `message` explains why."},"RateLimitedResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"message":{"type":"string"}},"required":["success","message"],"description":"Too many requests. Carries `Retry-After` and `X-RateLimit-*` headers."},"LoginRequest":{"type":"object","properties":{"credentials":{"$ref":"#/components/schemas/LoginCredentials"},"client_app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application the authorization code is issued for","example":"my-web-app"},"code_challenge":{"type":"string","minLength":43,"maxLength":1024,"description":"PKCE `S256` code challenge (RFC 7636) the authorization code is bound to"},"challenge_time":{"type":"number","minimum":0,"description":"Unix epoch milliseconds when the PKCE verifier was created; stale challenges are refused at redemption"},"redirect_uri":{"type":["string","null"],"format":"uri","description":"OAuth2 `redirect_uri` bound to the authorization code. Required for third-party client apps and must be registered for the app; omitted (or null) only for the auth server's own `/account` flow."},"nonce":{"type":["string","null"],"minLength":1,"maxLength":512,"pattern":"^[\\x20-\\x7E]+$","description":"OIDC login nonce (OIDC Core §3.1.2.1), echoed in the id_token at redemption. Optional."},"scope":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[\\x21\\x23-\\x5B\\x5D-\\x7E]+(?: [\\x21\\x23-\\x5B\\x5D-\\x7E]+)*$","description":"Requested scopes, space delimited (RFC 6749 §3.3). The server re-derives the granted subset; absent, or naming no supported scope, is a plain OAuth 2.1 grant without an id_token.","example":"openid profile email"}},"required":["credentials","client_app_id","code_challenge","challenge_time"],"additionalProperties":false,"description":"Unknown keys are rejected."},"LoginCredentials":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Account e-mail address; trimmed and lower-cased before lookup","example":"jane@example.com"},"password":{"type":"string","minLength":10,"maxLength":255,"description":"Account password (must satisfy the password policy)"}},"required":["email","password"],"additionalProperties":false},"RegisterRequest":{"type":"object","properties":{"credentials":{"$ref":"#/components/schemas/LoginCredentials"},"invite_code":{"type":"string","minLength":8,"description":"Invite code. Required when the `invite_code_required` server setting is on; the superuser invite code creates the first administrator."},"client_app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application the authorization code is issued for","example":"my-web-app"},"code_challenge":{"type":"string","minLength":43,"maxLength":1024,"description":"PKCE `S256` code challenge (RFC 7636) the authorization code is bound to"},"challenge_time":{"type":"number","minimum":0,"description":"Unix epoch milliseconds when the PKCE verifier was created; stale challenges are refused at redemption"},"redirect_uri":{"type":["string","null"],"format":"uri","description":"OAuth2 `redirect_uri` bound to the authorization code. Required for third-party client apps and must be registered for the app; omitted (or null) only for the auth server's own `/account` flow."},"nonce":{"type":["string","null"],"minLength":1,"maxLength":512,"pattern":"^[\\x20-\\x7E]+$","description":"OIDC login nonce (OIDC Core §3.1.2.1), echoed in the id_token at redemption. Optional."},"scope":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[\\x21\\x23-\\x5B\\x5D-\\x7E]+(?: [\\x21\\x23-\\x5B\\x5D-\\x7E]+)*$","description":"Requested scopes, space delimited (RFC 6749 §3.3). The server re-derives the granted subset; absent, or naming no supported scope, is a plain OAuth 2.1 grant without an id_token.","example":"openid profile email"}},"required":["credentials","client_app_id","code_challenge","challenge_time"],"additionalProperties":false,"description":"Unknown keys are rejected."},"MfaChallengeExpiredResult":{"type":"object","properties":{"kind":{"type":"string","enum":["challenge_expired"]},"success":{"type":"boolean"},"message":{"type":"string"}},"required":["kind","success","message"],"additionalProperties":false,"description":"The MFA challenge no longer exists (expired, exhausted its attempts, or already completed): the user has to log in again."},"MfaLoginVerifyRequest":{"type":"object","properties":{"challenge_id":{"type":"string","format":"uuid"},"client_app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"},"proof":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["totp"]},"factor_id":{"type":"string","format":"uuid"},"code":{"type":"string","pattern":"^\\d{6}$/u"}},"required":["type","factor_id","code"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["webauthn"]},"factor_id":{"type":"string","format":"uuid"},"assertion":{"type":"object","properties":{"id":{"type":"string","minLength":1},"rawId":{"type":"string","minLength":1},"response":{"type":"object","properties":{},"additionalProperties":{}},"authenticatorAttachment":{"type":"string"},"clientExtensionResults":{"type":"object","properties":{},"additionalProperties":{}},"type":{"type":"string","minLength":1}},"required":["id","rawId","response","type"],"additionalProperties":{}}},"required":["type","factor_id","assertion"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["recovery_code"]},"recovery_code":{"type":"string","minLength":8,"maxLength":64}},"required":["type","recovery_code"],"additionalProperties":false}]}},"required":["challenge_id","client_app_id","proof"],"additionalProperties":false,"description":"The `challenge_id` from the `mfa_required` login response, the same `client_app_id` the login was for, and one proof: a 6-digit TOTP code for a factor, a passkey assertion (obtained with the options from `POST /api/auth/mfa/webauthn/options`), or a single-use recovery code."},"WebauthnLoginOptions":{"type":"object","properties":{"options":{"type":"object","properties":{},"additionalProperties":{}}},"required":["options"],"additionalProperties":false,"description":"The `PublicKeyCredentialRequestOptionsJSON` to hand to `navigator.credentials.get()` verbatim; `allowCredentials` lists every passkey the user enrolled."},"WebauthnLoginOptionsRequest":{"type":"object","properties":{"challenge_id":{"type":"string","format":"uuid"},"client_app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"}},"required":["challenge_id","client_app_id"],"additionalProperties":false,"description":"The `challenge_id` from the `mfa_required` login response and the `client_app_id` the login was for. Unknown keys are rejected."},"LogoutResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"error":{"type":"boolean","enum":[false]},"message":{"type":"string"}},"required":["success","error","message"]},"BadRequestResponse":{"anyOf":[{"$ref":"#/components/schemas/ValidationErrorResponse"},{"$ref":"#/components/schemas/ErrorResponse"}]},"ValidationErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string","enum":["validation_error"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"location":{"type":"string","enum":["params","query","headers","body"]},"path":{"type":"string"},"message":{"type":"string"},"code":{"type":"string"}},"required":["location","path","message","code"]}}},"required":["success","error","message","issues"]},"GenerateAuthorizationCodeResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"authorization_code":{"type":"string","description":"Redeem at `POST /api/oidc/token` with the PKCE verifier"}},"required":["success","authorization_code"]},"AuthorizationCodeRefusal":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"message":{"type":"string"},"error_id":{"type":"string","enum":["pkce_challenge_expired","invalid_redirect_uri"]}},"required":["success","message"],"description":"`error_id` identifies the refusal: an expired PKCE challenge or a missing / unregistered `redirect_uri`."},"GenerateAuthorizationCodeRequest":{"type":"object","properties":{"client_app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application the authorization code is issued for","example":"my-web-app"},"code_challenge":{"type":"string","minLength":43,"maxLength":1024,"description":"PKCE `S256` code challenge (RFC 7636) the authorization code is bound to"},"code_challenge_method":{"type":"string","enum":["S256"]},"challenge_time":{"type":"number","minimum":0,"description":"Unix epoch milliseconds when the PKCE verifier was created; expired challenges are refused"},"redirect_uri":{"type":["string","null"],"format":"uri","description":"OAuth2 `redirect_uri` bound to the authorization code. Required for third-party client apps and must be registered for the app; omitted (or null) only when the auth server itself is the requesting app."},"nonce":{"type":["string","null"],"minLength":1,"maxLength":512,"pattern":"^[\\x20-\\x7E]+$","description":"OIDC login nonce (OIDC Core §3.1.2.1), echoed in the id_token at redemption. Optional."},"scope":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[\\x21\\x23-\\x5B\\x5D-\\x7E]+(?: [\\x21\\x23-\\x5B\\x5D-\\x7E]+)*$","description":"Requested scopes, space delimited (RFC 6749 §3.3). The server re-derives the granted subset; absent, or naming no supported scope, is a plain OAuth 2.1 grant without an id_token.","example":"openid profile email"}},"required":["client_app_id","code_challenge","code_challenge_method","challenge_time"],"additionalProperties":false,"description":"Unknown keys are rejected."},"SuccessMessageResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"]},"PasswordResetRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"E-mail address of the account","example":"jane@example.com"}},"required":["email"],"additionalProperties":false,"description":"Unknown keys are rejected."},"ValidationIssuesErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"message":{"type":"string"},"errors":{"type":"array","items":{},"description":"zod issues, present when the body failed schema validation"}},"required":["success","message"]},"PasswordResetConfirmRequest":{"type":"object","properties":{"token":{"type":"string","format":"uuid","description":"The reset token from the e-mailed link (`?token=`)"},"new_password":{"type":"string","minLength":10,"maxLength":255,"description":"New password (must satisfy the password policy)"}},"required":["token","new_password"],"additionalProperties":false,"description":"Unknown keys are rejected."},"EmailVerificationRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"E-mail address of the account","example":"jane@example.com"}},"required":["email"],"additionalProperties":false,"description":"Unknown keys are rejected."},"EmailVerificationConfirmRequest":{"type":"object","properties":{"token":{"type":"string","format":"uuid","description":"The verification token from the e-mailed link (`?token=`)"}},"required":["token"],"additionalProperties":false,"description":"Unknown keys are rejected."},"MfaStatus":{"type":"object","properties":{"enabled":{"type":"boolean"},"factors":{"type":"array","items":{"type":"object","properties":{"factor_id":{"type":"string","format":"uuid"},"factor_type":{"type":"string","enum":["totp","webauthn"]},"verified_at":{"type":"integer","exclusiveMinimum":0}},"required":["factor_id","factor_type"],"additionalProperties":false}},"recovery_codes_remaining":{"type":"integer","minimum":0}},"required":["enabled","factors","recovery_codes_remaining"],"additionalProperties":false,"description":"Account-wide MFA status: every verified factor plus the number of unused recovery codes. `enabled` mirrors `factors.length > 0`."},"MfaFactorStatus":{"type":"object","properties":{"enabled":{"type":"boolean"},"pending":{"type":"boolean"},"factor_id":{"type":"string","format":"uuid"},"factor_type":{"type":"string","enum":["totp","webauthn"]},"verified_at":{"type":"integer","exclusiveMinimum":0}},"required":["enabled","pending"],"additionalProperties":false,"description":"Status of one factor type. `enabled` means a verified factor of that type exists; `pending` means an enrollment was started but not confirmed yet. `factor_id` / `factor_type` are present whenever a factor row exists, `verified_at` (Unix epoch milliseconds) only when enabled."},"MfaTotpEnrollment":{"type":"object","properties":{"factor_id":{"type":"string","format":"uuid"},"factor_type":{"type":"string","enum":["totp"]},"otpauth_url":{"type":"string","format":"uri"},"qr_code_data_url":{"type":"string","minLength":1},"secret":{"type":"string","minLength":16}},"required":["factor_id","factor_type","otpauth_url","qr_code_data_url","secret"],"additionalProperties":false,"description":"A pending TOTP enrollment: the base32 secret, the `otpauth://` URL and a PNG data URL of its QR code to show the user, plus the `factor_id` to confirm the enrollment with."},"MfaVerifyEnrollmentResult":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"recovery_codes":{"type":"array","items":{"type":"string","minLength":8,"maxLength":64}},"recovery_codes_issued":{"type":"boolean"}},"required":["success","recovery_codes","recovery_codes_issued"],"additionalProperties":false,"description":"Outcome of confirming a factor (or regenerating recovery codes). `recovery_codes_issued` tells whether `recovery_codes` carries freshly minted codes to display; when false the user's existing codes still apply and the array is empty."},"MfaVerifyTotpEnrollmentRequest":{"type":"object","properties":{"factor_id":{"type":"string","format":"uuid"},"code":{"type":"string","pattern":"^\\d{6}$/u"}},"required":["factor_id","code"],"additionalProperties":false},"MfaFactorRemoved":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]},"MfaRemoveTotpFactorRequest":{"type":"object","properties":{"code":{"type":"string","pattern":"^\\d{6}$/u"}},"required":["code"],"additionalProperties":false},"MfaRegenerateRecoveryCodesRequest":{"type":"object","properties":{"factor_id":{"type":"string","format":"uuid"},"code":{"type":"string","pattern":"^\\d{6}$/u"}},"required":["factor_id","code"],"additionalProperties":false},"MfaWebauthnCredentialList":{"type":"object","properties":{"credentials":{"type":"array","items":{"type":"object","properties":{"factor_id":{"type":"string","format":"uuid"},"label":{"type":["string","null"]},"created_at":{"type":"integer","exclusiveMinimum":0},"last_used_at":{"type":["integer","null"],"exclusiveMinimum":0}},"required":["factor_id","label","created_at","last_used_at"],"additionalProperties":false}}},"required":["credentials"],"additionalProperties":false,"description":"The caller's verified passkeys. Pending (unconfirmed) enrollments are not listed."},"MfaWebauthnEnrollOptions":{"type":"object","properties":{"factor_id":{"type":"string","format":"uuid"},"options":{"type":"object","properties":{},"additionalProperties":{}}},"required":["factor_id","options"],"additionalProperties":false,"description":"A pending passkey enrollment: the `PublicKeyCredentialCreationOptionsJSON` to hand to `navigator.credentials.create()` verbatim, plus the `factor_id` to confirm the enrollment with."},"MfaVerifyPasskeyEnrollmentRequest":{"type":"object","properties":{"factor_id":{"type":"string","format":"uuid"},"label":{"type":"string","minLength":1,"maxLength":64},"attestation":{"type":"object","properties":{"id":{"type":"string","minLength":1},"rawId":{"type":"string","minLength":1},"response":{"type":"object","properties":{},"additionalProperties":{}},"authenticatorAttachment":{"type":"string"},"clientExtensionResults":{"type":"object","properties":{},"additionalProperties":{}},"type":{"type":"string","minLength":1}},"required":["id","rawId","response","type"],"additionalProperties":{}}},"required":["factor_id","attestation"],"additionalProperties":false},"MfaWebauthnStepUpOptions":{"type":"object","properties":{"options":{"type":"object","properties":{},"additionalProperties":{}}},"required":["options"],"additionalProperties":false,"description":"The `PublicKeyCredentialRequestOptionsJSON` to hand to `navigator.credentials.get()` verbatim for a step-up passkey assertion."},"MfaRemovePasskeyRequest":{"type":"object","properties":{"proof":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["totp"]},"factor_id":{"type":"string","format":"uuid"},"code":{"type":"string","pattern":"^\\d{6}$/u"}},"required":["type","factor_id","code"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["webauthn"]},"factor_id":{"type":"string","format":"uuid"},"assertion":{"type":"object","properties":{"id":{"type":"string","minLength":1},"rawId":{"type":"string","minLength":1},"response":{"type":"object","properties":{},"additionalProperties":{}},"authenticatorAttachment":{"type":"string"},"clientExtensionResults":{"type":"object","properties":{},"additionalProperties":{}},"type":{"type":"string","minLength":1}},"required":["id","rawId","response","type"],"additionalProperties":{}}},"required":["type","factor_id","assertion"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["recovery_code"]},"recovery_code":{"type":"string","minLength":8,"maxLength":64}},"required":["type","recovery_code"],"additionalProperties":false}],"description":"Step-up proof: a current TOTP code (`type: totp`), a passkey assertion for the challenge issued by `POST /api/user/mfa/webauthn/authenticate-options` (`type: webauthn`), or an unused recovery code (`type: recovery_code`)."}},"required":["proof"],"additionalProperties":false},"OidcProviderMetadata":{"type":"object","properties":{"issuer":{"type":"string","description":"Issuer identifier; byte-identical to the `iss` claim of issued id_tokens (no trailing slash).","example":"https://auth.example.com"},"authorization_endpoint":{"type":"string","description":"The authorization endpoint","example":"https://auth.example.com/api/oidc/authorize"},"token_endpoint":{"type":"string","description":"The token endpoint","example":"https://auth.example.com/api/oidc/token"},"userinfo_endpoint":{"type":"string","description":"The userinfo endpoint","example":"https://auth.example.com/api/oidc/userinfo"},"introspection_endpoint":{"type":"string","description":"RFC 7662 token introspection endpoint","example":"https://auth.example.com/api/oidc/introspect"},"jwks_uri":{"type":"string","description":"Public RS256 id_token verification keys","example":"https://auth.example.com/api/oidc/jwks"},"registration_endpoint":{"type":"string","description":"RFC 7591 dynamic client registration endpoint. Present only while the `allow_dynamic_client_registration` server setting is on.","example":"https://auth.example.com/api/oidc/register"},"response_types_supported":{"type":"array","items":{"type":"string"},"example":["code"]},"response_modes_supported":{"type":"array","items":{"type":"string"},"example":["query"]},"grant_types_supported":{"type":"array","items":{"type":"string"},"example":["authorization_code","refresh_token","client_credentials"]},"subject_types_supported":{"type":"array","items":{"type":"string"},"example":["public"]},"id_token_signing_alg_values_supported":{"type":"array","items":{"type":"string"},"example":["RS256"]},"scopes_supported":{"type":"array","items":{"type":"string"},"example":["openid","email","profile"]},"token_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"},"example":["none","client_secret_basic","client_secret_post"]},"introspection_endpoint_auth_methods_supported":{"type":"array","items":{"type":"string"},"example":["client_secret_basic","client_secret_post"]},"code_challenge_methods_supported":{"type":"array","items":{"type":"string"},"example":["S256"]},"claims_supported":{"type":"array","items":{"type":"string"}},"authorization_response_iss_parameter_supported":{"type":"boolean","description":"RFC 9207: every authorization response carries `iss`.","example":true},"request_parameter_supported":{"type":"boolean","example":false},"request_uri_parameter_supported":{"type":"boolean","example":false}},"required":["issuer","authorization_endpoint","token_endpoint","userinfo_endpoint","introspection_endpoint","jwks_uri","response_types_supported","response_modes_supported","grant_types_supported","subject_types_supported","id_token_signing_alg_values_supported","scopes_supported","token_endpoint_auth_methods_supported","introspection_endpoint_auth_methods_supported","code_challenge_methods_supported","claims_supported","authorization_response_iss_parameter_supported","request_parameter_supported","request_uri_parameter_supported"],"additionalProperties":{}},"OidcJsonWebKeySet":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/OidcJsonWebKey"}}},"required":["keys"]},"OidcJsonWebKey":{"type":"object","properties":{"kty":{"type":"string","description":"Key type","example":"RSA"},"kid":{"type":"string","description":"Key id; matches the `kid` header of id_tokens signed with it."},"alg":{"type":"string","example":"RS256"},"use":{"type":"string","example":"sig"},"n":{"type":"string","description":"RSA modulus (base64url)"},"e":{"type":"string","description":"RSA public exponent (base64url)","example":"AQAB"}},"required":["kty","kid","alg","use"],"additionalProperties":{},"description":"A public verification key (RFC 7517); never carries private members."},"OidcJwksErrorResponse":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"OAuthErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"OAuth 2.0 error code, e.g. `invalid_request`, `invalid_client`, `invalid_grant`, `unauthorized_client`, `unsupported_grant_type`, `invalid_scope`, `invalid_target`, `access_denied`, `server_error`.","example":"invalid_request"},"error_description":{"type":"string","description":"Human readable explanation of the error."}},"required":["error"],"description":"OAuth 2.0 error response (RFC 6749 §5.2). Carries `Cache-Control: no-store` and `Pragma: no-cache`."},"OidcTokenResponse":{"type":"object","properties":{"access_token":{"type":"string","description":"Encrypted (JWE) access token; opaque to the client."},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer","description":"Access token lifetime in seconds."},"refresh_token":{"type":"string","description":"Omitted for `client_credentials` and when `refresh_token_delivery=http_only_cookie`."},"refresh_token_expires_in":{"type":"integer","description":"@schemavaults/auth-server extension: seconds until the (possibly cookie-delivered) refresh token expires."},"scope":{"type":"string","description":"Granted scope; omitted when nothing was granted (plain OAuth 2.1 grant)."},"id_token":{"type":"string","description":"RS256-signed id_token; only on an `authorization_code` grant whose scope includes `openid`."}},"required":["access_token","token_type","expires_in"],"additionalProperties":{}},"OidcTokenRequest":{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token","client_credentials"],"description":"Which grant to redeem."},"client_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"The client application id. May be omitted when the client authenticates with `client_secret_basic` (the id then comes from the `Authorization` header).","example":"my-web-app"},"client_secret":{"type":"string","description":"`client_secret_post` authentication for confidential clients (apps with a registered client secret)."},"code":{"type":"string","description":"`authorization_code`: the code from the authorization response."},"redirect_uri":{"type":"string","description":"`authorization_code`: must equal the `redirect_uri` of the authorization request."},"code_verifier":{"type":"string","description":"`authorization_code`: the PKCE code verifier (RFC 7636)."},"refresh_token":{"type":"string","description":"`refresh_token`: the refresh token to rotate. Browser SDK clients that chose cookie delivery send it as the `refresh_token_<client_id>` cookie instead."},"scope":{"type":"string","description":"`refresh_token` / `client_credentials`: requested scope, which may only narrow the originally granted scope."},"resource":{"type":"string","description":"RFC 8707 resource indicator, as extended by @schemavaults/auth-server: the URL of a registered API server; the `access_token` is then minted for that audience instead of the reserved userinfo audience. At most one per request.","example":"https://api.example.com"},"refresh_token_delivery":{"type":"string","enum":["inline","http_only_cookie"],"description":"@schemavaults/auth-server extension: `http_only_cookie` sets the refresh token as the HTTP-only `refresh_token_<client_id>` cookie (plus a JS-readable expiry marker) and omits `refresh_token` from the body. Default `inline`."}},"required":["grant_type"]},"OidcUserinfoClaims":{"type":"object","properties":{"sub":{"type":"string","description":"Subject identifier in the `<auth_server_app_id>|<uid>` form; always present and identical to the id_token's `sub`.","example":"schemavaults-auth|8f1c2d3e-..."},"email":{"type":"string","description":"With the `email` scope."},"email_verified":{"type":"boolean","description":"With the `email` scope."},"name":{"type":"string","description":"With the `profile` scope, when set."},"given_name":{"type":"string"},"middle_name":{"type":"string"},"family_name":{"type":"string"},"preferred_username":{"type":"string"}},"required":["sub"],"additionalProperties":{},"description":"OIDC Core §5.3.2 claims, filtered by the access token's granted scope."},"OidcUserinfoErrorResponse":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_token","insufficient_scope"],"description":"RFC 6750 §3.1 error code; the details are in the `WWW-Authenticate` challenge."}},"required":["error"]},"OidcIntrospectionResponse":{"anyOf":[{"type":"object","properties":{"active":{"type":"boolean","enum":[false]}},"required":["active"]},{"type":"object","properties":{"active":{"type":"boolean","enum":[true]},"scope":{"type":"string","description":"Space-delimited granted scope; absent for tokens from a plain OAuth 2.1 grant."},"client_id":{"type":"string","description":"The client application the token was issued to."},"username":{"type":"string","description":"The resource owner's email; only when the `email` scope was granted."},"token_type":{"type":"string","enum":["Bearer"],"description":"Present for access tokens only."},"exp":{"type":"integer","description":"Expiry, seconds since the Unix epoch."},"iat":{"type":"integer","description":"Issued at, seconds since the Unix epoch."},"sub":{"type":"string","description":"Subject in the `<auth_server_app_id>|<uid>` form."},"aud":{"type":"string"},"iss":{"type":"string"},"jti":{"type":"string"}},"required":["active","client_id","exp","iat","sub","aud","iss"],"additionalProperties":{}}],"description":"RFC 7662 §2.2 introspection response."},"OidcIntrospectionRequest":{"type":"object","properties":{"token":{"type":"string","description":"REQUIRED. The access or refresh token to introspect."},"token_type_hint":{"type":"string","enum":["access_token","refresh_token"],"description":"Accepted but unused: the token kind is read from the token itself."},"client_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"The confidential client's id; may be omitted with `client_secret_basic`."},"client_secret":{"type":"string","description":"`client_secret_post` authentication."}},"required":["token"]},"DynamicClientRegistrationResponse":{"type":"object","properties":{"client_id":{"type":"string","minLength":1},"client_secret":{"type":"string","minLength":1},"client_id_issued_at":{"type":"integer","minimum":0},"client_secret_expires_at":{"type":"integer","minimum":0},"redirect_uris":{"type":"array","items":{"type":"string"},"minItems":1},"client_name":{"type":"string"},"token_endpoint_auth_method":{"type":"string","enum":["none","client_secret_basic","client_secret_post"]},"grant_types":{"type":"array","items":{"type":"string","enum":["authorization_code","refresh_token"]}},"response_types":{"type":"array","items":{"type":"string","enum":["code"]}},"client_uri":{"type":"string"},"logo_uri":{"type":"string"},"tos_uri":{"type":"string"},"policy_uri":{"type":"string"},"contacts":{"type":"array","items":{"type":"string"}},"scope":{"type":"string"},"software_id":{"type":"string"},"software_version":{"type":"string"}},"required":["client_id","client_id_issued_at","redirect_uris","client_name","token_endpoint_auth_method","grant_types","response_types"],"additionalProperties":{},"description":"RFC 7591 §3.2.1 registration response. `client_secret` is returned once, only for confidential clients; `client_secret_expires_at` is 0 (secrets do not expire)."},"DynamicClientRegistrationError":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_redirect_uri","invalid_client_metadata"]},"error_description":{"type":"string"}},"required":["error"],"description":"RFC 7591 §3.2.2 error: `invalid_redirect_uri` or `invalid_client_metadata`."},"DynamicClientRegistrationRequest":{"type":"object","properties":{"redirect_uris":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50,"description":"REQUIRED. Absolute URIs without a fragment: `https`, `http` loopback-IP URIs and, when the deployment allows them, `http://localhost` URIs and private-use scheme URIs.","example":["https://app.example.com/oauth/callback"]},"client_name":{"type":"string","description":"Display name; derived from the first redirect URI when absent."},"token_endpoint_auth_method":{"type":"string","enum":["none","client_secret_basic","client_secret_post"],"description":"Default `client_secret_basic` (RFC 7591 §2); `none` registers a public PKCE-only client."},"grant_types":{"type":"array","items":{"type":"string","enum":["authorization_code","refresh_token"]},"description":"Default `[\"authorization_code\"]`; must include `authorization_code`."},"response_types":{"type":"array","items":{"type":"string","enum":["code"]},"description":"Default `[\"code\"]`."},"client_uri":{"type":"string","maxLength":2048,"format":"uri","description":"The client's home page."},"logo_uri":{"type":"string","maxLength":2048,"format":"uri","description":"Logo to show on consent screens."},"tos_uri":{"type":"string","maxLength":2048,"format":"uri","description":"Terms of service."},"policy_uri":{"type":"string","maxLength":2048,"format":"uri","description":"Privacy policy."},"contacts":{"type":"array","items":{"type":"string","minLength":1,"maxLength":320},"maxItems":20,"description":"Ways to contact the people responsible for the client."},"scope":{"type":"string","maxLength":1024,"description":"Space-separated scopes the client intends to request (recorded, not enforced)."},"software_id":{"type":"string","maxLength":255},"software_version":{"type":"string","maxLength":255}},"required":["redirect_uris"],"additionalProperties":{},"description":"Unknown members are ignored (RFC 7591 §2). `jwks`, `jwks_uri` and `software_statement` are not supported and refused with `invalid_client_metadata`."},"UserProfileResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"profile":{"type":"object","properties":{"username":{"type":"string","minLength":3,"maxLength":32,"pattern":"^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$"},"first_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"middle_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"last_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"display_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"}},"additionalProperties":false}},"required":["success","profile"],"additionalProperties":false,"description":"The caller's profile name fields; absent fields are unset."},"UpdateUserProfileRequest":{"type":"object","properties":{"username":{"type":["string","null"],"minLength":3,"maxLength":32,"pattern":"^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$"},"first_name":{"type":["string","null"],"minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"middle_name":{"type":["string","null"],"minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"last_name":{"type":["string","null"],"minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"display_name":{"type":["string","null"],"minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"}},"additionalProperties":false,"description":"The new profile name fields; omitted or null fields are cleared."},"OrganizationMembershipRoleDetails":{"type":"object","properties":{"organization_id":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$"},"organization_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9]([a-zA-Z0-9 _-]*[a-zA-Z0-9])?$"},"role":{"type":"string"},"created_at":{"type":"integer","minimum":0},"joined_at":{"type":"integer","minimum":0}},"required":["organization_id","organization_name","role","created_at","joined_at"],"additionalProperties":false},"UserPendingInvitation":{"type":"object","properties":{"invitation_id":{"type":"string","format":"uuid"},"organization_id":{"type":"string"},"organization_name":{"type":"string"},"inviter_uid":{"type":"string"},"inviter_email":{"type":"string"},"status":{"type":"string","enum":["pending","accepted","declined","revoked","expired"]},"created_at":{"type":"number"},"expires_at":{"type":"number"}},"required":["invitation_id","organization_id","organization_name","inviter_uid","inviter_email","status","created_at","expires_at"]},"ListAppsQueryResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"list":{"type":"array","items":{"type":"object","properties":{"app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client Application ID"},"app_name":{"type":"string","maxLength":128},"app_description":{"type":"string","maxLength":512},"created_at":{"type":"number","minimum":0},"public":{"type":"boolean"},"hardcoded":{"type":"boolean"},"web":{"type":"boolean"},"owner_type":{"type":"string","enum":["platform","organization","user","dynamic-client-registration"]},"owner_organization_id":{"type":["string","null"]},"owner_uid":{"type":["string","null"],"format":"uuid"},"created_by":{"type":["string","null"],"format":"uuid"},"client_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"logo_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"tos_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"policy_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"contacts":{"type":["array","null"],"items":{"type":"string","maxLength":320},"maxItems":20},"grant_types":{"type":["array","null"],"items":{"type":"string","enum":["authorization_code","refresh_token"]}},"response_types":{"type":["array","null"],"items":{"type":"string","enum":["code"]}},"token_endpoint_auth_method":{"type":["string","null"],"enum":["none","client_secret_basic","client_secret_post",null]},"software_id":{"type":["string","null"],"maxLength":255},"software_version":{"type":["string","null"],"maxLength":255},"registered_scope":{"type":["string","null"],"maxLength":1024},"client_id_issued_at":{"type":["integer","null"],"minimum":0}},"required":["app_id","app_name","app_description","created_at","public","hardcoded","web"],"additionalProperties":false}}},"required":["success","message","list"]},"ResourceCreationResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"resource_id":{"type":"string","description":"Identifier of the created / affected resource"}},"required":["success","message","resource_id"]},"SchemaVaultsAppDefinition":{"type":"object","properties":{"app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client Application ID"},"app_name":{"type":"string","maxLength":128},"app_description":{"type":"string","maxLength":512},"created_at":{"type":"number","minimum":0},"public":{"type":"boolean"},"hardcoded":{"type":"boolean"},"web":{"type":"boolean"},"owner_type":{"type":"string","enum":["platform","organization","user","dynamic-client-registration"]},"owner_organization_id":{"type":["string","null"]},"owner_uid":{"type":["string","null"],"format":"uuid"},"created_by":{"type":["string","null"],"format":"uuid"},"client_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"logo_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"tos_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"policy_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"contacts":{"type":["array","null"],"items":{"type":"string","maxLength":320},"maxItems":20},"grant_types":{"type":["array","null"],"items":{"type":"string","enum":["authorization_code","refresh_token"]}},"response_types":{"type":["array","null"],"items":{"type":"string","enum":["code"]}},"token_endpoint_auth_method":{"type":["string","null"],"enum":["none","client_secret_basic","client_secret_post",null]},"software_id":{"type":["string","null"],"maxLength":255},"software_version":{"type":["string","null"],"maxLength":255},"registered_scope":{"type":["string","null"],"maxLength":1024},"client_id_issued_at":{"type":["integer","null"],"minimum":0}},"required":["app_id","app_name","app_description","created_at","public","hardcoded","web"],"additionalProperties":false},"AppAuthorizationStatusResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"authorized":{"type":"boolean","description":"Whether the caller has authorized the app to receive tokens on their behalf"}},"required":["success","authorized"]},"AuthorizeAppRequest":{"type":"object","properties":{"state":{"type":"string","minLength":1,"maxLength":512,"pattern":"^[\\x20-\\x7E]+$","description":"The OAuth2 `state` nonce of the in-flight authorization request. Validated, logged in development, never persisted."}},"additionalProperties":false},"ListAppDomainsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"list":{"type":"array","items":{"type":"object","properties":{"app_domain_ref_id":{"type":"string","format":"uuid"},"app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"},"domain":{"type":"string","maxLength":255},"environment":{"type":"string","enum":["development","staging","test","production"]},"created_at":{"type":"number","minimum":0},"hardcoded":{"type":"boolean"}},"required":["app_domain_ref_id","app_id","domain","environment","created_at","hardcoded"],"additionalProperties":false}}},"required":["success","message","list"]},"SchemaVaultsAppDomainRef":{"type":"object","properties":{"app_domain_ref_id":{"type":"string","format":"uuid"},"app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"},"domain":{"type":"string","maxLength":255},"environment":{"type":"string","enum":["development","staging","test","production"]},"created_at":{"type":"number","minimum":0},"hardcoded":{"type":"boolean"}},"required":["app_domain_ref_id","app_id","domain","environment","created_at","hardcoded"],"additionalProperties":false},"ListAppCallbackUrlsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"list":{"type":"array","items":{"type":"object","properties":{"app_callback_url_ref_id":{"type":"string","format":"uuid"},"app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"},"callback_url":{"type":"string","maxLength":2048,"format":"uri"},"environment":{"type":"string","enum":["development","staging","test","production"]},"created_at":{"type":"number","minimum":0}},"required":["app_callback_url_ref_id","app_id","callback_url","environment","created_at"],"additionalProperties":false}}},"required":["success","message","list"]},"SchemaVaultsAppCallbackUrlRef":{"type":"object","properties":{"app_callback_url_ref_id":{"type":"string","format":"uuid"},"app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"},"callback_url":{"type":"string","maxLength":2048,"format":"uri"},"environment":{"type":"string","enum":["development","staging","test","production"]},"created_at":{"type":"number","minimum":0}},"required":["app_callback_url_ref_id","app_id","callback_url","environment","created_at"],"additionalProperties":false},"ClientSecretMetadataResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"has_client_secret":{"type":"boolean","description":"Whether the app currently has a client secret (is a confidential client)"},"created_at":{"type":"number","description":"First-generation time (ms since epoch); absent without a secret"},"updated_at":{"type":"number","description":"Last generation / rotation time (ms since epoch); absent without a secret"}},"required":["success","has_client_secret"]},"ClientSecretGenerationResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"client_secret":{"type":"string","description":"The plaintext client secret: shown once, never retrievable again"}},"required":["success","message","client_secret"]},"AppServiceAccountResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"service_account":{"$ref":"#/components/schemas/AppServiceAccountSummary"},"has_client_secret":{"type":"boolean","description":"Whether the app can use the client_credentials grant right now (has a client secret)"}},"required":["success","service_account","has_client_secret"]},"AppServiceAccountSummary":{"type":["object","null"],"properties":{"uid":{"type":"string","description":"The service account's user id (`sub` / `uid` of its tokens)"},"email":{"type":"string","description":"Synthetic, undeliverable address under the reserved `.invalid` TLD"},"created_at":{"type":"number","description":"Unix epoch milliseconds"},"disabled":{"type":"boolean","description":"A disabled service account is refused the client_credentials grant"}},"required":["uid","email","created_at","disabled"],"description":"Null until the first client_credentials grant (or explicit creation)"},"AppServiceAccountCreationResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"service_account":{"$ref":"#/components/schemas/AppServiceAccountSummary"},"created":{"type":"boolean","description":"False when the service account already existed"}},"required":["success","message","service_account","created"]},"ListApiServersResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"list":{"type":"array","items":{"$ref":"#/components/schemas/ApiServerDefinition"}}},"required":["success","message","list"]},"ApiServerDefinition":{"type":"object","properties":{"api_server_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"},"api_server_name":{"type":"string","maxLength":64},"api_server_description":{"type":"string","maxLength":512},"created_at":{"type":"number","minimum":0},"public":{"type":"boolean"},"hardcoded":{"type":"boolean"},"owner_type":{"type":"string","enum":["platform","organization","user","dynamic-client-registration"]},"owner_organization_id":{"type":["string","null"]},"owner_uid":{"type":["string","null"],"format":"uuid"},"created_by":{"type":["string","null"],"format":"uuid"},"allow_dynamic_clients":{"type":"boolean"},"resource_url_match_mode":{"type":"string","enum":["exact","prefix"]}},"required":["api_server_id","api_server_name","api_server_description","created_at","public","hardcoded"],"additionalProperties":false,"description":"An API server (resource server) registration: identity, listing visibility, ownership (platform / organization / user) and dynamic-client policy."},"ApiServerResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"api_server":{"$ref":"#/components/schemas/ApiServerDefinition"}},"required":["success","api_server"]},"ApiServerDynamicClientPolicyUpdate":{"type":"object","properties":{"allow_dynamic_clients":{"type":"boolean","description":"Whether clients registered through RFC 7591 dynamic client registration may obtain access tokens for this API server (as an RFC 8707 `resource`) without an explicit app-to-API connection"},"resource_url_match_mode":{"type":"string","enum":["exact","prefix"],"description":"Whether an RFC 8707 `resource` URL must equal a registered domain (`exact`) or may be any URL under one (`prefix`)"}},"additionalProperties":false},"ListApiServerDomainsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"list":{"type":"array","items":{"$ref":"#/components/schemas/ApiServerDomainRef"}}},"required":["success","message","list"]},"ApiServerDomainRef":{"type":"object","properties":{"api_server_domain_ref_id":{"type":"string","format":"uuid"},"api_server_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"},"domain":{"type":"string","maxLength":255},"environment":{"type":"string","enum":["development","staging","test","production"]},"created_at":{"type":"number","minimum":0},"hardcoded":{"type":"boolean"}},"required":["api_server_domain_ref_id","api_server_id","domain","environment","created_at","hardcoded"],"additionalProperties":false,"description":"A domain an API server is reachable at in one app environment."},"AppToApiServerConnectionResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"is_allowed":{"type":"boolean","description":"Whether the client application is connected to (may request tokens for) the API server"}},"required":["success","is_allowed"]},"JwksAccessKeyMetadataResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"key_metadata":{"anyOf":[{"$ref":"#/components/schemas/JwksAccessKeyStatus"},{"type":"boolean","enum":[false]}],"description":"Metadata of the active key, or `false` when no JWKS access key has been generated yet"}},"required":["success","key_metadata"]},"JwksAccessKeyStatus":{"type":"object","properties":{"key_id":{"type":"string","description":"Identifier of the active JWKS access key pair"},"created_at":{"type":"number","description":"Unix epoch milliseconds"},"is_active":{"type":"boolean"}},"required":["key_id","created_at","is_active"]},"JwksAccessKeyGeneratedResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"key_id":{"type":"string","description":"Identifier of the new key pair"},"private_key":{"type":"string","description":"PEM-encoded private key. Shown exactly once; the auth server keeps only the public key."}},"required":["success","message","key_id","private_key"]},"OrganizationDefinition":{"type":"object","properties":{"organization_id":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$"},"name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9]([a-zA-Z0-9 _-]*[a-zA-Z0-9])?$"},"created_at":{"type":"number","exclusiveMinimum":0},"created_by":{"type":["string","null"],"format":"uuid"}},"required":["organization_id","name","created_at"],"additionalProperties":false},"OrganizationMember":{"type":"object","properties":{"membership_declaration_id":{"type":"string","description":"Id of the membership row"},"organization_id":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$"},"uid":{"type":"string","format":"uuid","description":"The member's user id"},"role":{"type":"string","description":"Membership role in the organization: `owner`, `member`, or `admin` (the virtual role platform administrators hold in the owner organization).","example":"member"},"membership_created_at":{"type":"number","description":"Unix epoch milliseconds the membership was created"},"email":{"type":"string","format":"email"},"email_verified":{"type":"boolean"},"admin":{"type":"boolean","description":"Whether the member is a platform administrator"},"disabled":{"type":"boolean","description":"Whether the member's account is disabled"}},"required":["membership_declaration_id","organization_id","uid","role","membership_created_at","email"]},"UpdateOrganizationMemberRoleRequest":{"type":"object","properties":{"role":{"type":"string","description":"Membership role in the organization: `owner`, `member`, or `admin` (the virtual role platform administrators hold in the owner organization).","example":"member"}},"required":["role"]},"OrganizationInvitationListEntry":{"type":"object","properties":{"invitation_id":{"type":"string","format":"uuid"},"organization_id":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$"},"organization_name":{"type":"string"},"inviter_uid":{"type":"string","format":"uuid"},"inviter_email":{"type":"string","format":"email","description":"E-mail address of the inviting user"},"invitee_uid":{"type":"string","format":"uuid"},"invitee_email":{"type":"string","format":"email","description":"E-mail address of the invited user"},"status":{"type":"string","enum":["pending","accepted","declined","revoked","expired"]},"created_at":{"type":"number","exclusiveMinimum":0},"expires_at":{"type":"number","exclusiveMinimum":0},"responded_at":{"type":["number","null"],"exclusiveMinimum":0}},"required":["invitation_id","organization_id","inviter_uid","inviter_email","invitee_uid","invitee_email","status","created_at","expires_at"]},"OrganizationInvitation":{"type":"object","properties":{"invitation_id":{"type":"string","format":"uuid"},"organization_id":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$"},"organization_name":{"type":"string"},"inviter_uid":{"type":"string","format":"uuid"},"inviter_email":{"type":"string","format":"email"},"invitee_uid":{"type":"string","format":"uuid"},"invitee_email":{"type":"string","format":"email"},"status":{"type":"string","enum":["pending","accepted","declined","revoked","expired"]},"created_at":{"type":"number","exclusiveMinimum":0},"expires_at":{"type":"number","exclusiveMinimum":0},"responded_at":{"type":["number","null"],"exclusiveMinimum":0}},"required":["invitation_id","organization_id","inviter_uid","invitee_uid","status","created_at","expires_at"],"description":"An invitation for a user to join an organization."},"CreateOrganizationInvitationRequest":{"type":"object","properties":{"input_mode":{"type":"string","enum":["email","uid"],"description":"How `identifier` names the invitee: by e-mail address or by user id","example":"email"},"identifier":{"type":"string","minLength":1,"description":"The invitee's e-mail address (`input_mode: email`) or user id (`input_mode: uid`)","example":"teammate@example.com"}},"required":["input_mode","identifier"]},"RespondToOrganizationInvitationRequest":{"type":"object","properties":{"action":{"type":"string","enum":["accept","decline"],"example":"accept"}},"required":["action"]},"AdminUserRecord":{"type":"object","properties":{"email":{"type":"string","format":"email"},"email_verified":{"type":"boolean"},"uid":{"type":"string","format":"uuid"},"created_at":{"type":"number","minimum":0},"invite_code":{"type":"string","minLength":8,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"admin":{"type":"boolean"},"disabled":{"type":"boolean"},"tokens_valid_after":{"type":"number","minimum":0},"username":{"type":"string","minLength":3,"maxLength":32,"pattern":"^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$"},"first_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"middle_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"last_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"display_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"service_account_app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"}},"required":["email","uid","created_at"],"additionalProperties":false,"description":"A registered user as stored by the auth server (not the OIDC `UserData` shape: there is no `sub`, clients derive it from `uid`)."},"AdminIssuedToken":{"type":"object","properties":{"jti":{"type":"string","description":"Token id (`jti` claim)"},"uid":{"type":"string"},"token_type":{"type":"string","enum":["access","refresh"],"description":"Kind of issued token"},"client_app_id":{"type":"string"},"audience":{"type":"string","description":"API server id or resource URL the token was minted for"},"grant_type":{"type":"string","enum":["refresh_token","authorization_code","client_credentials"]},"issued_at":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Unix epoch milliseconds (a number, or its decimal string form from the database driver)","example":1735689600000},"expires_at":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Unix epoch milliseconds (a number, or its decimal string form from the database driver)","example":1735689600000},"refresh_jti":{"type":["string","null"],"description":"For access tokens: the jti of the refresh token minted in the same grant; null otherwise"}},"required":["jti","uid","token_type","client_app_id","audience","grant_type","issued_at","expires_at","refresh_jti"]},"InviteCodeDefinition":{"type":"object","properties":{"invite_code":{"type":"string","minLength":8,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"},"created_at":{"type":"number","minimum":0},"max_uses":{"type":"integer","exclusiveMinimum":0},"description":{"type":"string","maxLength":128},"created_by":{"type":"string","format":"uuid"}},"required":["invite_code","created_at","max_uses"],"additionalProperties":false},"ServerSettingRecord":{"type":"object","properties":{"key":{"type":"string","example":"invite_codes_required"},"value":{"description":"The setting's current value (type depends on the key)"},"valueType":{"type":"string","example":"boolean"},"description":{"type":["string","null"]},"updatedAt":{"type":"number","description":"Unix epoch milliseconds"},"updatedBy":{"type":["string","null"],"description":"uid of the administrator who last changed it"}},"required":["key","valueType","description","updatedAt","updatedBy"]},"UpdateServerSettingRequest":{"type":"object","properties":{"value":{"description":"New value; validated against the setting's own schema"},"description":{"type":"string"}}},"BrandingAssetMetadataRecord":{"type":"object","properties":{"key":{"type":"string","example":"favicon"},"label":{"type":"string","example":"Favicon"},"description":{"type":"string"},"allowedContentTypes":{"type":"array","items":{"type":"string"},"example":["image/png","image/svg+xml"]},"maxSizeBytes":{"type":"integer","description":"Upload limit in raw bytes"},"recommendedDimensions":{"type":"string","example":"32x32 or 48x48"},"hasCustomAsset":{"type":"boolean","description":"Whether an administrator uploaded a custom asset for this slot"},"contentType":{"type":["string","null"]},"contentHash":{"type":["string","null"],"description":"SHA-256 hex digest of the uploaded bytes (null when using the default)"},"sizeBytes":{"type":["number","null"]},"updatedAt":{"type":["number","null"],"description":"Unix epoch milliseconds"},"updatedBy":{"type":["string","null"],"description":"uid of the administrator who uploaded it"}},"required":["key","label","description","allowedContentTypes","maxSizeBytes","recommendedDimensions","hasCustomAsset","contentType","contentHash","sizeBytes","updatedAt","updatedBy"]},"BrandingAssetUploadResult":{"type":"object","properties":{"key":{"type":"string","example":"favicon"},"contentType":{"type":"string","example":"image/png"},"contentHash":{"type":"string","description":"SHA-256 hex digest of the uploaded bytes"},"sizeBytes":{"type":"integer"},"updatedAt":{"type":"number","description":"Unix epoch milliseconds"}},"required":["key","contentType","contentHash","sizeBytes","updatedAt"]},"AdminServerTrace":{"type":"object","properties":{"event_id":{"type":"string","format":"uuid"},"op_name":{"type":"string","minLength":1},"op_category":{"type":"string","enum":["database_query","http_response","http_request","subroutine"]},"start_time":{"type":"number","minimum":0},"end_time":{"type":"number","minimum":0}},"required":["event_id","op_name","op_category","start_time","end_time"],"additionalProperties":false,"description":"A timing trace captured by the server; `start_time` / `end_time` are Unix epoch milliseconds."},"AdminServerTraceOperation":{"type":"object","properties":{"op_name":{"type":"string","minLength":1,"example":"POST /api/auth/login"},"op_category":{"type":"string","enum":["database_query","http_response","http_request","subroutine"]},"count":{"type":"integer","minimum":0,"description":"Traces recorded for the operation in the window"},"last_seen":{"type":"number","minimum":0,"description":"Start of the operation's most recent trace (Unix epoch milliseconds)"}},"required":["op_name","op_category","count","last_seen"]},"DailyAdminReportResult":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"users_count":{"type":"integer"},"organizations_count":{"type":"integer"},"errors_count":{"type":"integer"},"top_most_active_users_count":{"type":"integer"},"top_most_popular_apps_count":{"type":"integer"},"top_most_popular_apis_count":{"type":"integer"},"window_start":{"type":"string","format":"date-time","description":"Start of the 24h reporting window"},"window_end":{"type":"string","format":"date-time","description":"End of the 24h reporting window (now)"}},"required":["ok","users_count","organizations_count","errors_count","top_most_active_users_count","top_most_popular_apps_count","top_most_popular_apis_count","window_start","window_end"]},"DailyAdminReportFailure":{"type":"object","properties":{"ok":{"type":"boolean","enum":[false]},"message":{"type":"string"}},"required":["ok","message"]},"JsonWebKeySet":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/JsonWebKey"}}},"required":["keys"],"description":"The keys the auth server uses for one API server audience: the RS256 signing keys and the JWE key-wrapping key.","example":{"keys":[{"kty":"RSA","kid":"0b6c4a1e-3f7a-4d0e-9b2a-7f3f2d1c8e5a","alg":"RS256","use":"sig","n":"...","e":"AQAB"}]}},"JsonWebKey":{"type":"object","properties":{"kty":{"type":"string","description":"Key type","example":"RSA"},"kid":{"type":"string","description":"Key id, matched against the token header"},"alg":{"type":"string","description":"Algorithm the key is meant for","example":"RS256"},"use":{"type":"string","description":"`sig` (signature) or `enc` (encryption)","example":"sig"}},"description":"A JSON Web Key (RFC 7517 §4); carries the key material in addition to the members listed here."},"ResourceServerBadRequestResponse":{"anyOf":[{"$ref":"#/components/schemas/ValidationErrorResponse"},{"$ref":"#/components/schemas/ErrorResponse"},{"$ref":"#/components/schemas/ResourceServerErrorResponse"}]},"ResourceServerErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string","description":"Human readable reason","example":"Unauthorized"}},"required":["success","error"],"description":"Error envelope of the resource-server endpoints: `success` is false and `error` explains why."},"ResourceServerAllowedOriginsResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"api_server_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$"},"environment":{"type":"string","enum":["development","staging","test","production"],"description":"The app environment whose client app domains were collected"},"origins":{"type":"array","items":{"type":"string","example":"https://app.example.com"},"description":"Sorted, de-duplicated origins"}},"required":["api_server_id","environment","origins"]}},"required":["success","data"]},"OrganizationMemberRoleResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"organization_id":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$"},"uid":{"type":"string","format":"uuid"},"role":{"type":["string","null"],"description":"The user's role in the organization, or null when not a member (or no such user)","example":"member"}},"required":["organization_id","uid","role"]}},"required":["success","data"]},"EnvironmentResponse":{"type":"object","properties":{"environment":{"type":"string","enum":["development","staging","test","production"]}},"required":["environment"]},"BrandingConfigResponse":{"type":"object","properties":{"error":{"type":"boolean","enum":[false]},"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/AuthServerBrandingConfig"}},"required":["error","success","message","data"]},"AuthServerBrandingConfig":{"type":"object","properties":{"friendly_name":{"type":"string","description":"Human-friendly name of this deployment (`SCHEMAVAULTS_AUTH_SERVER_FRIENDLY_NAME`)","example":"SchemaVaults"},"theme_colors":{"type":"array","prefixItems":[{"type":"string","description":"Gradient start (`SCHEMAVAULTS_AUTH_SERVER_THEME_COLOR_1`)"},{"type":"string","description":"Gradient end (`SCHEMAVAULTS_AUTH_SERVER_THEME_COLOR_2`)"}],"description":"[from, to] CSS color strings of the theme gradient (page background, wordmark)","example":["#1e40af","#b91c1c"]}},"required":["friendly_name","theme_colors"]},"InviteCodeRequiredResponse":{"type":"object","properties":{"error":{"type":"boolean","enum":[false]},"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"boolean","description":"true when registration requires an invite code"}},"required":["error","success","message","data"]},"ConfigurationErrorResponse":{"type":"object","properties":{"error":{"type":"boolean","enum":[true]},"success":{"type":"boolean","enum":[false]},"message":{"type":"string"}},"required":["error","success","message"]}},"parameters":{}},"paths":{"/api/auth/login":{"post":{"operationId":"post_api_auth_login","summary":"Log in with email and password","description":"Verifies the credentials and starts a PKCE authorization-code grant for `client_app_id`: on success the authorization code is bound to the code challenge, the `redirect_uri`, the granted scopes and the nonce, and the auth server's HTTP-only session cookie is set. Accounts with a verified second factor get an `mfa_required` challenge instead (complete it at `POST /api/auth/mfa/verify`). Wrong credentials and unknown accounts answer the same 401. Rate limited per IP + e-mail (a sliding window plus a lockout counter of failed attempts).","tags":["Authentication"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Credentials travel in the body. An existing auth server session cookie is only used to refuse signing in as a different user."},"requestBody":{"required":true,"description":"The body is parsed by the handler itself so its error format stays stable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}}},"responses":{"200":{"description":"Authenticated (authorization code issued) or an MFA challenge was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateSuccessResult"}}}},"400":{"description":"Invalid JSON, a body that fails schema validation (raw zod issues), a missing or unregistered `redirect_uri`, or the client IP could not be determined","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateBadRequest"}}}},"401":{"description":"Invalid email or password (constant body, so accounts cannot be enumerated)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateFailureResult"}}}},"403":{"description":"The account is disabled, or the browser already holds another user's session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateFailureResult"}}}},"429":{"description":"Too many requests; `Retry-After` and `X-RateLimit-*` headers say when to retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to verify the credentials or to issue the authorization code","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AuthenticateFailureResult"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}}}}},"/api/auth/register":{"post":{"operationId":"post_api_auth_register","summary":"Register a new account","description":"Creates an account for the e-mail address and, like login, starts a PKCE authorization-code grant for `client_app_id` (authorization code + the auth server's HTTP-only session cookie) and sends the verification e-mail. When the `invite_code_required` server setting is on an invite code is mandatory; a supplied code is always validated and consumed. E-mail addresses on the reserved service-account domain are refused. Rate limited per IP.","tags":["Authentication"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Refused while the browser already holds an auth server session."},"requestBody":{"required":true,"description":"The body is parsed by the handler itself so its error format stays stable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}}},"responses":{"200":{"description":"The account was created and the user is authenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticatedResult"}}}},"400":{"description":"Invalid JSON, a body that fails schema validation (raw zod issues), a missing / malformed / exhausted invite code, a reserved e-mail domain, a missing or unregistered `redirect_uri`, or the client IP could not be determined","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateBadRequest"}}}},"403":{"description":"The browser already holds an auth server session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateFailureResult"}}}},"404":{"description":"The invite code does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"An account with this e-mail address already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateFailureResult"}}}},"429":{"description":"Too many requests; `Retry-After` and `X-RateLimit-*` headers say when to retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to create the account or to issue the authorization code","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AuthenticateFailureResult"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}}}}},"/api/auth/mfa/verify":{"post":{"operationId":"post_api_auth_mfa_verify","summary":"Complete a login MFA challenge","description":"Second step of a login that answered `mfa_required`: presents a TOTP code, a passkey assertion or a recovery code for the pending challenge. Each wrong proof costs one of the challenge's attempts; when they run out (or the challenge expired) the answer is 410 and the user must log in again. On success the challenge is deleted and the same authorization code + session cookie a password-only login would have produced are issued. Rate limited per IP.","tags":["Authentication"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"The challenge id issued by `POST /api/auth/login` is the credential."},"requestBody":{"required":true,"description":"The body is parsed by the handler itself so its error format stays stable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaLoginVerifyRequest"}}}},"responses":{"200":{"description":"The proof was accepted and the user is authenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticatedResult"}}}},"400":{"description":"Invalid JSON, a body that fails schema validation (raw zod issues), a challenge issued for another client app, or the client IP could not be determined","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateBadRequest"}}}},"401":{"description":"The proof was wrong; `message` says how many attempts remain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateFailureResult"}}}},"410":{"description":"The challenge expired, was already completed, or exhausted its attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaChallengeExpiredResult"}}}},"429":{"description":"Too many requests; `Retry-After` and `X-RateLimit-*` headers say when to retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to evaluate the proof or to issue the authorization code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateFailureResult"}}}}}}},"/api/auth/mfa/webauthn/options":{"post":{"operationId":"post_api_auth_mfa_webauthn_options","summary":"Start a passkey assertion for a login MFA challenge","description":"Issues WebAuthn assertion options for the user behind a pending login MFA challenge and binds the assertion nonce to that challenge, so the signed assertion can be submitted as a `webauthn` proof to `POST /api/auth/mfa/verify`. Refuses users without a verified passkey. Rate limited per IP (shares the MFA verification budget).","tags":["Authentication"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"The challenge id issued by `POST /api/auth/login` is the credential."},"requestBody":{"required":true,"description":"The body is parsed by the handler itself so its error format stays stable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebauthnLoginOptionsRequest"}}}},"responses":{"200":{"description":"Assertion options for the user's passkeys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebauthnLoginOptions"}}}},"400":{"description":"Invalid JSON, a body that fails schema validation (raw zod issues), a challenge issued for another client app, or the client IP could not be determined","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ZodIssuesResponse"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"409":{"description":"The user has no verified passkey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"The challenge expired or does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests; `Retry-After` and `X-RateLimit-*` headers say when to retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to create the assertion options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/logout/{client_app_id}":{"post":{"operationId":"post_api_auth_logout_client_app_id","summary":"Log out of a client application","description":"Ends the browser's session with `client_app_id`: when the app's refresh token cookie is present and verifies, that refresh token and the access tokens minted with it are revoked server-side (other devices and other apps stay signed in), then the app's refresh token cookies are cleared. Browser callers (an `Origin` header is present) must come from an origin registered for the app and receive credentialed CORS headers; web apps must always send an `Origin`. Answer `OPTIONS` for the CORS preflight.","tags":["Authentication"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Needs no credentials: an expired or missing refresh token still clears the cookies."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application to log out of","example":"my-web-app"},"required":true,"description":"Client application to log out of","name":"client_app_id","in":"path"}],"responses":{"200":{"description":"The refresh token cookies were cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogoutResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"403":{"description":"The `Origin` is not registered for the app, or a web app sent no `Origin`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to clear the cookies","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/whoami/{client_app_id}":{"get":{"operationId":"get_api_auth_whoami_client_app_id","summary":"Get the signed-in user","description":"Returns the complete, current `UserData` of the caller (reloaded from the database rather than taken from the token's claims). Besides the auth server's own session and access tokens it accepts the per-client-app refresh token cookie issued to `client_app_id` during the OAuth2 grant, so SDK clients can sync their current user without an auth server session. Browser callers from an origin registered for the app receive credentialed CORS headers on every response (401 included); an authenticated request from an unregistered origin is refused with 403. Answer `OPTIONS` for the CORS preflight.","tags":["Authentication"],"security":[{"schemavaults-client-app-refresh-token-cookie":[]},{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-client-app-refresh-token-cookie","schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Credentials are checked before the path parameter, so an unauthenticated caller always gets 401 whatever `client_app_id` it sent."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application whose session the caller holds","example":"my-web-app"},"required":true,"description":"Client application whose session the caller holds","name":"client_app_id","in":"path"}],"responses":{"200":{"description":"The caller's user data","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"user":{"type":"object","properties":{"uid":{"type":"string","format":"uuid"},"sub":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"email_verified":{"type":"boolean"},"username":{"type":"string","minLength":3,"maxLength":32,"pattern":"^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$"},"first_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"middle_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"last_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"display_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001F\\u007F]*$"},"admin":{"type":"boolean"},"phone_number":{"type":"string","minLength":10,"maxLength":15},"phone_verified":{"type":"boolean"},"disabled":{"type":"boolean"},"service_account":{"type":"boolean"},"created_at":{"type":"integer","exclusiveMinimum":0},"invite_code":{"type":"string","minLength":8,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$"}},"required":["uid","sub","email","created_at"],"additionalProperties":false}},"required":["success","user"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the request is authenticated but comes from an origin not registered for the app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/session/generate-authorization-code":{"post":{"operationId":"post_api_auth_session_generate_authorization_code","summary":"Issue an authorization code for the current session","description":"Mints a PKCE authorization code for `client_app_id` on behalf of the signed-in user without re-entering credentials (the OAuth2 authorize bridge and the consent screen use it once the user has authorized the app). The code is bound to the code challenge, the `redirect_uri`, the granted scopes and the nonce exactly as a fresh login would bind them.","tags":["Authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateAuthorizationCodeRequest"}}}},"responses":{"200":{"description":"The authorization code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateAuthorizationCodeResponse"}}}},"400":{"description":"The body failed validation, the PKCE challenge expired, or the `redirect_uri` is missing / not registered for the app","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ValidationErrorResponse"},{"$ref":"#/components/schemas/AuthorizationCodeRefusal"}]}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to generate the authorization code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/reset-password/request":{"post":{"operationId":"post_api_auth_reset_password_request","summary":"Request a password reset e-mail","description":"E-mails a single-use password reset link (valid for one hour) to the address when an account exists for it. The response is the same whether or not the account exists, so addresses cannot be enumerated; service accounts are silently ignored. Rate limited per e-mail address.","tags":["Authentication"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null},"requestBody":{"required":true,"description":"The body is parsed by the handler itself so its error format stays stable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetRequest"}}}},"responses":{"200":{"description":"Accepted (whether or not an account exists for the address)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid JSON or a body that fails schema validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests; `Retry-After` and `X-RateLimit-*` headers say when to retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Unexpected failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/reset-password/confirm":{"post":{"operationId":"post_api_auth_reset_password_confirm","summary":"Reset the password with an e-mailed token","description":"Consumes a password reset token and sets the new password. Every session and token issued before the reset is invalidated (the user's `tokens_valid_after` watermark moves), so the user has to log in again everywhere. Rate limited per IP.","tags":["Authentication"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"The single-use reset token is the credential."},"requestBody":{"required":true,"description":"The body is parsed by the handler itself so its error format stays stable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetConfirmRequest"}}}},"responses":{"200":{"description":"The password was reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid JSON, a body that fails schema validation (`errors` lists the zod issues), an invalid or expired token, or the client IP could not be determined","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationIssuesErrorResponse"}}}},"429":{"description":"Too many requests; `Retry-After` and `X-RateLimit-*` headers say when to retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to reset the password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/verify-email/request":{"post":{"operationId":"post_api_auth_verify_email_request","summary":"Request a verification e-mail","description":"Sends a fresh verification link to the address when an unverified account exists for it. The response is the same whether the account exists, is already verified, or not, so addresses cannot be enumerated.","tags":["Authentication"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailVerificationRequest"}}}},"responses":{"200":{"description":"Accepted (whether or not an unverified account exists for the address)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"500":{"description":"Unexpected failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/verify-email/confirm":{"post":{"operationId":"post_api_auth_verify_email_confirm","summary":"Confirm an e-mail address with an e-mailed token","description":"Consumes an e-mail verification token and marks the account's address as verified. Rate limited per IP.","tags":["Authentication"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"The single-use verification token is the credential."},"requestBody":{"required":true,"description":"The body is parsed by the handler itself so its error format stays stable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailVerificationConfirmRequest"}}}},"responses":{"200":{"description":"The address was verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"Invalid JSON, a body that fails schema validation (`errors` lists the zod issues), an invalid or expired token, or the client IP could not be determined","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationIssuesErrorResponse"}}}},"429":{"description":"Too many requests; `Retry-After` and `X-RateLimit-*` headers say when to retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to verify the address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/status":{"get":{"operationId":"get_api_user_mfa_status","summary":"Get my MFA status","description":"Lists the caller's verified MFA factors (authenticator apps and passkeys) and how many recovery codes remain unused. Pending enrollments are not listed; use `GET /api/user/mfa/status/{factor_type}` for those. The payload is returned raw, without a `success` envelope.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"responses":{"200":{"description":"The caller's MFA status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaStatus"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load MFA status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/status/{factor_type}":{"get":{"operationId":"get_api_user_mfa_status_factor_type","summary":"Get my status for one MFA factor type","description":"Reports whether the caller has a verified factor of the given type (`enabled`) or an enrollment in progress (`pending`); the two are mutually exclusive. Unlike `GET /api/user/mfa/status` this includes unconfirmed enrollments, so the settings UI can resume a pending setup. The payload is returned raw, without a `success` envelope.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","enum":["totp","webauthn"],"description":"The factor type to report on","example":"totp"},"required":true,"description":"The factor type to report on","name":"factor_type","in":"path"}],"responses":{"200":{"description":"The caller's status for that factor type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaFactorStatus"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load MFA status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/totp/enroll":{"post":{"operationId":"post_api_user_mfa_totp_enroll","summary":"Start a TOTP enrollment","description":"Creates a pending authenticator-app factor for the caller and returns the secret, the `otpauth://` URL and its QR code. Confirm it with `POST /api/user/mfa/totp/verify-enrollment`. Refused while the caller already has a verified factor; abandoned enrollments are swept first. Any request body is ignored. Rate limited per user.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"responses":{"200":{"description":"The pending enrollment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaTotpEnrollment"}}}},"400":{"description":"The client IP address could not be determined","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"MFA is already enabled on the account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many enrollment attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to start the enrollment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/totp/verify-enrollment":{"post":{"operationId":"post_api_user_mfa_totp_verify_enrollment","summary":"Confirm a TOTP enrollment","description":"Activates the pending authenticator-app factor named by `factor_id` once the caller submits a current code from it. Recovery codes are minted only when this becomes the caller's first verified factor (`recovery_codes_issued`); a security alert e-mail is sent.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerifyTotpEnrollmentRequest"}}}},"responses":{"200":{"description":"The factor is now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerifyEnrollmentResult"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"The code did not match the factor (or no valid session was presented)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such pending factor for the caller","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The factor is already verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to verify the enrollment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/totp/{factor_id}":{"delete":{"operationId":"delete_api_user_mfa_totp_factor_id","summary":"Remove a TOTP factor","description":"Deletes one of the caller's authenticator-app factors (verified or still pending). The request must carry a current code from that very factor as proof of control. Removing the last verified factor also discards the account's recovery codes. A security alert e-mail is sent.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"MFA factor id, as returned by the enrollment endpoints and `GET /api/user/mfa/status`","example":"0d3f0b8a-1f0e-4a8c-9a4e-2b3c4d5e6f70"},"required":true,"description":"MFA factor id, as returned by the enrollment endpoints and `GET /api/user/mfa/status`","name":"factor_id","in":"path"}],"requestBody":{"required":true,"description":"A current 6-digit code generated by the factor being removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaRemoveTotpFactorRequest"}}}},"responses":{"200":{"description":"The factor was removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaFactorRemoved"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"The code did not match the factor (or no valid session was presented)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such factor for the caller","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to remove the factor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/recovery-codes/regenerate":{"post":{"operationId":"post_api_user_mfa_recovery_codes_regenerate","summary":"Regenerate my recovery codes","description":"Replaces the caller's recovery codes with a fresh set, invalidating every previous code. The request must carry a current code from one of the caller's verified authenticator-app factors (`factor_id`). The response always has `recovery_codes_issued: true`.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"requestBody":{"required":true,"description":"The verified TOTP factor to prove control of, and a current code from it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaRegenerateRecoveryCodesRequest"}}}},"responses":{"200":{"description":"The new recovery codes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerifyEnrollmentResult"}}}},"400":{"description":"The body failed validation, or `factor_id` is not one of the caller's verified factors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"The code did not match the factor (or no valid session was presented)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to regenerate the recovery codes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/webauthn":{"get":{"operationId":"get_api_user_mfa_webauthn","summary":"List my passkeys","description":"Lists the caller's verified passkeys (WebAuthn credentials) with their label and usage timestamps. Pending enrollments are not listed. The payload is returned raw, without a `success` envelope.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"responses":{"200":{"description":"The caller's passkeys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaWebauthnCredentialList"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the passkeys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/webauthn/options":{"post":{"operationId":"post_api_user_mfa_webauthn_options","summary":"Start a passkey enrollment","description":"Creates a pending passkey factor for the caller and returns the WebAuthn registration options (`PublicKeyCredentialCreationOptionsJSON`) for `navigator.credentials.create()`; already enrolled passkeys are excluded so the authenticator will not register a duplicate. Confirm the enrollment with `POST /api/user/mfa/webauthn/verify-enrollment`; the challenge expires after a short time. Abandoned enrollments are swept first. Any request body is ignored. Rate limited per user and client IP.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"responses":{"200":{"description":"The pending enrollment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaWebauthnEnrollOptions"}}}},"400":{"description":"The client IP address could not be determined","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many enrollment attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to start the enrollment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/webauthn/verify-enrollment":{"post":{"operationId":"post_api_user_mfa_webauthn_verify_enrollment","summary":"Confirm a passkey enrollment","description":"Verifies the authenticator's attestation against the challenge issued by `POST /api/user/mfa/webauthn/options`, stores the credential and activates the pending passkey factor. The challenge is consumed whatever the outcome; an expired or missing challenge is a 410 and the enrollment must be started again. Recovery codes are minted only when this becomes the caller's first verified factor (`recovery_codes_issued`); a security alert e-mail is sent. Rate limited per user and client IP.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"requestBody":{"required":true,"description":"The pending `factor_id`, the `RegistrationResponseJSON` produced by `navigator.credentials.create()` and an optional label for the passkey.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerifyPasskeyEnrollmentRequest"}}}},"responses":{"200":{"description":"The passkey is now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerifyEnrollmentResult"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"The attestation could not be verified (or no valid session was presented)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such pending passkey factor for the caller","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The factor is already verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"The enrollment challenge was not found or expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many enrollment attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to verify the enrollment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/webauthn/authenticate-options":{"post":{"operationId":"post_api_user_mfa_webauthn_authenticate_options","summary":"Start a passkey step-up verification","description":"Issues WebAuthn authentication options (`PublicKeyCredentialRequestOptionsJSON`) restricted to the caller's enrolled passkeys, so a signed-in user can re-prove possession of one before a sensitive action such as `DELETE /api/user/mfa/webauthn/{factor_id}`. One step-up challenge is kept per user; each call replaces it. Refused when the caller has no verified passkey. Any request body is ignored. Rate limited per user and client IP.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"responses":{"200":{"description":"The assertion options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaWebauthnStepUpOptions"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The caller has no enrolled passkey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many step-up challenges requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"Failed to start the passkey verification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/mfa/webauthn/{factor_id}":{"delete":{"operationId":"delete_api_user_mfa_webauthn_factor_id","summary":"Remove a passkey","description":"Deletes one of the caller's passkeys. The request must carry a step-up proof of a current factor (any TOTP code, a fresh passkey assertion, or a recovery code); a passkey assertion consumes the step-up challenge whatever the outcome. Removing the last verified factor also discards the account's recovery codes. A security alert e-mail is sent.","tags":["Multi-factor authentication"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"MFA factor id, as returned by the enrollment endpoints and `GET /api/user/mfa/status`","example":"0d3f0b8a-1f0e-4a8c-9a4e-2b3c4d5e6f70"},"required":true,"description":"MFA factor id, as returned by the enrollment endpoints and `GET /api/user/mfa/status`","name":"factor_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaRemovePasskeyRequest"}}}},"responses":{"200":{"description":"The passkey was removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaFactorRemoved"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"The step-up proof was not accepted (or no valid session was presented)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such passkey for the caller","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to remove the passkey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/oidc/openid-configuration":{"get":{"operationId":"get_api_oidc_openid_configuration","summary":"OpenID Provider metadata (discovery)","description":"OIDC Discovery 1.0 §4 provider-configuration document. Relying parties normally fetch it at the spec-fixed paths `/.well-known/openid-configuration` and, for plain OAuth 2.0 clients (RFC 8414), `/.well-known/oauth-authorization-server`; both are rewritten to this route (OpenID Provider Metadata is a superset of RFC 8414 metadata, so one document serves both). `registration_endpoint` is advertised only while dynamic client registration is enabled by the `allow_dynamic_client_registration` server setting; a failure to read that setting degrades to not advertising it. Cached for an hour (`Cache-Control: public, max-age=3600`) and served with `Access-Control-Allow-Origin: *`.","tags":["OpenID Connect / OAuth 2.0"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Unauthenticated by design: the document is public."},"responses":{"200":{"description":"The provider metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderMetadata"}}}}}}},"/api/oidc/jwks":{"get":{"operationId":"get_api_oidc_jwks","summary":"id_token verification keys (JWKS)","description":"The OIDC `jwks_uri`: the RS256 verification PUBLIC keys of every active keyset for the reserved `oidc-userinfo` audience, which relying parties need to verify id_token signatures. Creates the first keyset on demand. Unlike `GET /api/jwks/{audience}` (which serves trusted resource servers the full keyset and requires a JWKS access assertion) this document is public and contains verification keys only. Cached briefly (`Cache-Control: public, max-age=300`) so rotated-in keysets propagate quickly; served with `Access-Control-Allow-Origin: *`.","tags":["OpenID Connect / OAuth 2.0"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Unauthenticated by design: public verification keys only."},"responses":{"200":{"description":"The JSON Web Key Set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcJsonWebKeySet"}}}},"500":{"description":"The signing keys could not be loaded or exported","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcJwksErrorResponse"}}}}}}},"/api/oidc/authorize":{"get":{"operationId":"get_api_oidc_authorize","summary":"Authorization endpoint","description":"The OAuth 2.0 / OpenID Connect authorization endpoint (RFC 6749 §3.1, OIDC Core §3.1.2). Validates the request and redirects the user-agent to the auth server's login / consent UI, which later redirects back to `redirect_uri` with `code`, `state` and `iss` (RFC 9207). PKCE `S256` is mandatory. Errors in `client_id` or `redirect_uri` are answered with a direct 400 (never a redirect); every later failure (`unsupported_response_type`, `invalid_scope`, `invalid_request`, `login_required`, `request_not_supported`, ...) redirects back to the validated `redirect_uri` with `error`, `error_description`, `state` and `iss` query parameters. Responses carry `Cache-Control: no-store`.","tags":["OpenID Connect / OAuth 2.0"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"No credentials: the resource owner authenticates on the login page this endpoint redirects to. The client is identified by `client_id` and its registered `redirect_uri`."},"parameters":[{"schema":{"type":"string","description":"REQUIRED. The client application id.","example":"my-web-app"},"required":false,"description":"REQUIRED. The client application id.","name":"client_id","in":"query"},{"schema":{"type":"string","description":"REQUIRED. Must exactly match a callback URL registered for the client app (http loopback URLs are port-agnostic per RFC 8252 §7.3).","example":"https://app.example.com/auth/callback"},"required":false,"description":"REQUIRED. Must exactly match a callback URL registered for the client app (http loopback URLs are port-agnostic per RFC 8252 §7.3).","name":"redirect_uri","in":"query"},{"schema":{"type":"string","description":"REQUIRED. Only `code` is supported.","example":"code"},"required":false,"description":"REQUIRED. Only `code` is supported.","name":"response_type","in":"query"},{"schema":{"type":"string","description":"OPTIONAL. Space-delimited scopes. With `openid` this is an OpenID Connect authentication request (an id_token is minted); without it a plain OAuth 2.1 authorization grant (access + refresh tokens only). Supported: `openid`, `email`, `profile`; unknown scopes are ignored.","example":"openid email profile"},"required":false,"description":"OPTIONAL. Space-delimited scopes. With `openid` this is an OpenID Connect authentication request (an id_token is minted); without it a plain OAuth 2.1 authorization grant (access + refresh tokens only). Supported: `openid`, `email`, `profile`; unknown scopes are ignored.","name":"scope","in":"query"},{"schema":{"type":"string","description":"RECOMMENDED. Opaque value echoed back on the redirect (also on error redirects)."},"required":false,"description":"RECOMMENDED. Opaque value echoed back on the redirect (also on error redirects).","name":"state","in":"query"},{"schema":{"type":"string","description":"OPTIONAL. Bound to the id_token's `nonce` claim (OIDC Core §3.1.2.1)."},"required":false,"description":"OPTIONAL. Bound to the id_token's `nonce` claim (OIDC Core §3.1.2.1).","name":"nonce","in":"query"},{"schema":{"type":"string","description":"REQUIRED. PKCE code challenge (RFC 7636); every client is treated as public."},"required":false,"description":"REQUIRED. PKCE code challenge (RFC 7636); every client is treated as public.","name":"code_challenge","in":"query"},{"schema":{"type":"string","description":"REQUIRED. Only `S256` is supported.","example":"S256"},"required":false,"description":"REQUIRED. Only `S256` is supported.","name":"code_challenge_method","in":"query"},{"schema":{"type":"string","description":"OPTIONAL. `none` is refused with `login_required` (silent authentication is not supported); other values are ignored."},"required":false,"description":"OPTIONAL. `none` is refused with `login_required` (silent authentication is not supported); other values are ignored.","name":"prompt","in":"query"},{"schema":{"type":"string","description":"Not supported: refused with `request_not_supported` (no JAR / RFC 9101)."},"required":false,"description":"Not supported: refused with `request_not_supported` (no JAR / RFC 9101).","name":"request","in":"query"},{"schema":{"type":"string","description":"Not supported: refused with `request_uri_not_supported`."},"required":false,"description":"Not supported: refused with `request_uri_not_supported`.","name":"request_uri","in":"query"},{"schema":{"type":"string","description":"Ignored at this endpoint. Send the RFC 8707 `resource` parameter to the token endpoint instead to mint the access token for a registered API server."},"required":false,"description":"Ignored at this endpoint. Send the RFC 8707 `resource` parameter to the token endpoint instead to mint the access token for a registered API server.","name":"resource","in":"query"}],"responses":{"302":{"description":"Redirect. On success `Location` is the auth server's login page carrying the bridged parameters (`app_id`, `code_challenge`, `code_challenge_method`, `challenge_time`, `redirect_uri`, `state`, `nonce`, `scope`); on a post-validation error it is the client's `redirect_uri` with `error`, `error_description`, `state` and `iss`.","headers":{"Cache-Control":{"schema":{"type":"string","example":"no-store"},"required":true},"Location":{"schema":{"type":"string","description":"Where the user-agent is sent next."},"required":true,"description":"Where the user-agent is sent next."}}},"400":{"description":"`client_id` is missing, malformed, unknown or not registered for web redirect flows (`invalid_request` / `unauthorized_client`), `redirect_uri` is missing, invalid or unregistered, `state` is malformed, or the client app could not be loaded (`server_error`).","headers":{"Cache-Control":{"schema":{"type":"string","example":"no-store"},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}}}}},"/api/oidc/token":{"post":{"operationId":"post_api_oidc_token","summary":"Token endpoint","description":"The OAuth 2.0 / OIDC token endpoint (RFC 6749 §3.2, form-encoded). Three grants: `authorization_code` (PKCE `code_verifier` required, `redirect_uri` must match; mints an id_token when the grant's scope includes `openid`), `refresh_token` (rotates the refresh token; the previous one is revoked), and `client_credentials` (confidential clients only; mints a machine-to-machine access token for the app's service account, no refresh token). @schemavaults/auth-server extensions: the RFC 8707 `resource` parameter mints the access token for a registered API server, and `refresh_token_delivery=http_only_cookie` delivers the refresh token as an HTTP-only cookie (`Set-Cookie`) instead of in the body; every response with a refresh token carries `refresh_token_expires_in`. Browser callers (with an `Origin` header) must come from one of the client app's registered origins and then receive a credentialed CORS allowance; other callers get `Access-Control-Allow-Origin: *`. `refresh_token` and `client_credentials` requests are rate limited per IP. Responses carry `Cache-Control: no-store`.","tags":["OpenID Connect / OAuth 2.0"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Client authentication per RFC 6749 §2.3: public clients send `client_id` only (PKCE is the security boundary); confidential clients (apps with a registered client secret) must authenticate with `client_secret_basic` (HTTP Basic `Authorization` header) or `client_secret_post` (`client_secret` form field). The handler performs this itself."},"requestBody":{"required":true,"description":"Form-encoded token request. Which fields are required depends on `grant_type`.","content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/OidcTokenRequest"}}}},"responses":{"200":{"description":"The token response (RFC 6749 §5.1 / OIDC Core §3.1.3.3)","headers":{"Cache-Control":{"schema":{"type":"string","example":"no-store"},"required":true},"Set-Cookie":{"schema":{"type":"string","description":"Refresh token cookies when `refresh_token_delivery=http_only_cookie` was requested."},"required":false,"description":"Refresh token cookies when `refresh_token_delivery=http_only_cookie` was requested."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcTokenResponse"}}}},"400":{"description":"OAuth error (`invalid_request`, `unsupported_grant_type`, `invalid_grant`, `invalid_scope`, `invalid_target`, `unauthorized_client`, ...), or the client IP could not be determined for rate limiting (`{ success: false, message }`).","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/OAuthErrorResponse"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"401":{"description":"Client authentication failed (`invalid_client`)","headers":{"WWW-Authenticate":{"schema":{"type":"string","description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."},"required":true,"description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"403":{"description":"The request came from an origin the client application has not registered (`invalid_request`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"429":{"description":"Rate limited (`refresh_token` / `client_credentials` grants)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"The token request could not be processed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}}}}},"/api/oidc/userinfo":{"get":{"operationId":"get_api_oidc_userinfo","summary":"Userinfo endpoint","description":"The OpenID Connect userinfo endpoint (OIDC Core §5.3). Presents the access token issued by the token endpoint as `Authorization: Bearer <access_token>`; the server decrypts and verifies it (only tokens minted for the reserved `oidc-userinfo` audience are accepted) and returns the claims permitted by the token's granted scope: `sub` always, `email` / `email_verified` with the `email` scope, and the profile name claims (read fresh from the user's profile) with the `profile` scope. Tokens from a plain OAuth 2.1 grant (no `openid` scope) are refused with 403 `insufficient_scope`. Served with `Access-Control-Allow-Origin: *` and `Cache-Control: no-store`. OIDC Core §5.3.1 allows POST as well as GET; form-body token delivery is not supported (the token must be in the `Authorization` header).","tags":["OpenID Connect / OAuth 2.0"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Bearer access token minted by `POST /api/oidc/token` for the reserved `oidc-userinfo` audience (RFC 6750 §2.1). The handler verifies it itself; the platform's session cookies are not accepted here."},"responses":{"200":{"description":"The claims the token's scope permits","headers":{"Cache-Control":{"schema":{"type":"string","example":"no-store"},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcUserinfoClaims"}}}},"401":{"description":"No `Authorization` header (`invalid_request`, challenge `Bearer`), or the bearer token is malformed, not a userinfo-audience token, expired, revoked or belongs to a disabled account (`invalid_token`)","headers":{"WWW-Authenticate":{"schema":{"type":"string","description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."},"required":true,"description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcUserinfoErrorResponse"}}}},"403":{"description":"The token is valid but was not granted the `openid` scope (`insufficient_scope`)","headers":{"WWW-Authenticate":{"schema":{"type":"string","description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."},"required":true,"description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcUserinfoErrorResponse"}}}}}},"post":{"operationId":"post_api_oidc_userinfo","summary":"Userinfo endpoint (POST)","description":"The OpenID Connect userinfo endpoint (OIDC Core §5.3). Presents the access token issued by the token endpoint as `Authorization: Bearer <access_token>`; the server decrypts and verifies it (only tokens minted for the reserved `oidc-userinfo` audience are accepted) and returns the claims permitted by the token's granted scope: `sub` always, `email` / `email_verified` with the `email` scope, and the profile name claims (read fresh from the user's profile) with the `profile` scope. Tokens from a plain OAuth 2.1 grant (no `openid` scope) are refused with 403 `insufficient_scope`. Served with `Access-Control-Allow-Origin: *` and `Cache-Control: no-store`. OIDC Core §5.3.1 allows POST as well as GET; form-body token delivery is not supported (the token must be in the `Authorization` header).","tags":["OpenID Connect / OAuth 2.0"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Bearer access token minted by `POST /api/oidc/token` for the reserved `oidc-userinfo` audience (RFC 6750 §2.1). The handler verifies it itself; the platform's session cookies are not accepted here."},"responses":{"200":{"description":"The claims the token's scope permits","headers":{"Cache-Control":{"schema":{"type":"string","example":"no-store"},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcUserinfoClaims"}}}},"401":{"description":"No `Authorization` header (`invalid_request`, challenge `Bearer`), or the bearer token is malformed, not a userinfo-audience token, expired, revoked or belongs to a disabled account (`invalid_token`)","headers":{"WWW-Authenticate":{"schema":{"type":"string","description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."},"required":true,"description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcUserinfoErrorResponse"}}}},"403":{"description":"The token is valid but was not granted the `openid` scope (`insufficient_scope`)","headers":{"WWW-Authenticate":{"schema":{"type":"string","description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."},"required":true,"description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcUserinfoErrorResponse"}}}}}}},"/api/oidc/introspect":{"post":{"operationId":"post_api_oidc_introspect","summary":"Token introspection","description":"The OAuth 2.0 token introspection endpoint (RFC 7662), advertised as `introspection_endpoint`. A confidential client POSTs an access or refresh token issued by this server and learns whether it is currently active plus its metadata (scope, client, subject, expiry). Tokens minted for other resource-API audiences, tokens issued to a different client, expired and revoked tokens all yield `{ \"active\": false }`. Public (PKCE-only) clients cannot introspect: without client authentication the endpoint would be open to token scanning. Responses carry `Cache-Control: no-store` and `Access-Control-Allow-Origin: *`.","tags":["OpenID Connect / OAuth 2.0"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Client authentication is REQUIRED (RFC 7662 §2.1): `client_secret_basic` (HTTP Basic `Authorization` header) or `client_secret_post` (`client_secret` form field) of an app with a registered client secret. The handler performs this itself; `none` is not accepted."},"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/OidcIntrospectionRequest"}}}},"responses":{"200":{"description":"The token's state","headers":{"Cache-Control":{"schema":{"type":"string","example":"no-store"},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcIntrospectionResponse"}}}},"400":{"description":"Not form-encoded, `token` missing, malformed `client_id`, or a malformed Basic `Authorization` header (`invalid_request`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"401":{"description":"No client identified, the client secret is wrong, or the client is not confidential (`invalid_client`)","headers":{"WWW-Authenticate":{"schema":{"type":"string","description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."},"required":true,"description":"The authentication challenge, e.g. `Bearer error=\"invalid_token\"` or `Basic realm=\"...\"`."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"500":{"description":"The introspection request could not be processed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}}}}},"/api/oidc/register":{"post":{"operationId":"post_api_oidc_register","summary":"Dynamic client registration","description":"OAuth 2.0 Dynamic Client Registration (RFC 7591 §3) for MCP and other OAuth clients. Off by default: the `allow_dynamic_client_registration` server setting must be on (the discovery document advertises `registration_endpoint` only then). A valid request creates an ownerless client application (`owner_type = dynamic-client-registration`, manageable by platform administrators only) with its redirect URIs registered as explicit callback URLs and, for confidential clients, a generated client secret. Registrations are rate limited per IP; bodies over 128 KiB are refused with 413. RFC 7592 configuration management is not implemented. Responses carry `Cache-Control: no-store` and `Access-Control-Allow-Origin: *`.","tags":["OpenID Connect / OAuth 2.0"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Open registration: no initial access token or other credential is required."},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DynamicClientRegistrationRequest"}}}},"responses":{"201":{"description":"The client was registered","headers":{"Cache-Control":{"schema":{"type":"string","example":"no-store"},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DynamicClientRegistrationResponse"}}}},"400":{"description":"The body is not a JSON object or the metadata is invalid (`invalid_client_metadata` / `invalid_redirect_uri`), or the client IP could not be determined for rate limiting (`{ success: false, message }`)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/DynamicClientRegistrationError"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"403":{"description":"Dynamic client registration is disabled on this server (`access_denied`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"413":{"description":"The request body exceeds 128 KiB (`invalid_client_metadata`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DynamicClientRegistrationError"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedResponse"}}}},"500":{"description":"The registration could not be processed (`server_error`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}}}}},"/api/user/profile":{"get":{"operationId":"get_api_user_profile","summary":"Get my profile","description":"Returns the caller's profile name fields (username, first/middle/last name, display name), read fresh from the database: the auth token payload does not carry them.","tags":["Account"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"responses":{"200":{"description":"The caller's profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The caller's account no longer exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"operationId":"put_api_user_profile","summary":"Replace my profile","description":"Replaces the caller's profile name fields. Full-replacement semantics: fields that are omitted or set to null are cleared. Unknown fields are rejected.","tags":["Account"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserProfileRequest"}}}},"responses":{"200":{"description":"The updated profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The caller's account no longer exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The requested username is already taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to update the profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/me/organizations":{"get":{"operationId":"get_api_me_organizations","summary":"List my organization memberships","description":"Lists the organizations the caller belongs to with their role in each (platform administrators also see their virtual `admin` membership of the owner organization). Answers with CORS headers so client applications may call it cross-origin with a bearer access token.","tags":["Account"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"responses":{"200":{"description":"The caller's memberships","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"memberships":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationMembershipRoleDetails"}}},"required":["memberships"]}},"required":["success","message","data"]}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the memberships","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/me/organizations/{organization_id}/role":{"get":{"operationId":"get_api_me_organizations_organization_id_role","summary":"Get my role in an organization","description":"Returns the caller's membership role in one organization; 404 when the caller is not a member (platform administrators hold the virtual `admin` role in the owner organization).","tags":["Account"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization id (URL-safe slug)","example":"acme-inc"},"required":true,"description":"Organization id (URL-safe slug)","name":"organization_id","in":"path"}],"responses":{"200":{"description":"The caller's role","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"organization_id":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$"},"role":{"type":"string","description":"Membership role in the organization: `owner`, `member`, or `admin` (the virtual role platform administrators hold in the owner organization).","example":"member"}},"required":["organization_id","role"]}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The caller is not a member of the organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to look up the membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/user/organizations":{"get":{"operationId":"get_api_user_organizations","summary":"List my organizations","description":"Lists the definitions of the organizations the caller is a member of (platform administrators also get the owner organization). Organizations that fail to load are skipped and recorded server-side. `GET /api/me/organizations` additionally reports the caller's role in each.","tags":["Account"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"responses":{"200":{"description":"The caller's organizations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"organizations":{"type":"array","items":{"type":"object","properties":{"organization_id":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$"},"name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9]([a-zA-Z0-9 _-]*[a-zA-Z0-9])?$"},"created_at":{"type":"number","exclusiveMinimum":0},"created_by":{"type":["string","null"],"format":"uuid"}},"required":["organization_id","name","created_at"],"additionalProperties":false}}},"required":["success","organizations"]}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/me/invitations":{"get":{"operationId":"get_api_me_invitations","summary":"List my pending organization invitations","tags":["Account"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"responses":{"200":{"description":"The caller's pending invitations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"invitations":{"type":"array","items":{"$ref":"#/components/schemas/UserPendingInvitation"}}},"required":["invitations"]}},"required":["success","message","data"]}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list invitations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps":{"get":{"operationId":"get_api_apps","summary":"List client applications","description":"Lists client applications selected by `list_apps_query_type`. Listing every app requires a platform administrator; listing an organization's apps requires membership of that organization (or administrator rights).","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","description":"Which apps to list: \"all\" (platform administrators only), \"public\" (publicly listed apps), \"authorized\" (apps the caller has authorized), \"org\" (apps owned by `organization_id`; members only), \"owned\" (apps owned by the caller's account) or \"accessible\" (every app the caller can reach by ownership). Required; an unknown value is a 400.","example":"public"},"required":false,"description":"Which apps to list: \"all\" (platform administrators only), \"public\" (publicly listed apps), \"authorized\" (apps the caller has authorized), \"org\" (apps owned by `organization_id`; members only), \"owned\" (apps owned by the caller's account) or \"accessible\" (every app the caller can reach by ownership). Required; an unknown value is a 400.","name":"list_apps_query_type","in":"query"},{"schema":{"type":"string","description":"The organization whose apps to list; required with `list_apps_query_type=org`.","example":"my-organization"},"required":false,"description":"The organization whose apps to list; required with `list_apps_query_type=org`.","name":"organization_id","in":"query"}],"responses":{"200":{"description":"The selected apps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAppsQueryResponse"}}}},"400":{"description":"Missing or unknown `list_apps_query_type`, a missing / malformed `organization_id` for the org query, or a malformed query string","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list apps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_apps","summary":"Create a client application","description":"Registers a new client application (OAuth client). The owner is resolved from the `owner_type` / `owner_organization_id` / `owner_uid` fields: platform-owned apps need a platform administrator, organization-owned apps an owner or admin of that organization, and user-owned apps require the `allow_user_owned_resource_creation` server setting. Apps flagged `hardcoded` cannot be created.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"requestBody":{"required":true,"description":"`created_by` and the ownership are derived from the caller and the requested owner fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaVaultsAppDefinition"}}}},"responses":{"200":{"description":"The app was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"An app with this id already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to create the app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}":{"get":{"operationId":"get_api_apps_app_id","summary":"Get a client application","description":"Loads one client application. Private apps are only visible to platform administrators, members of the owning organization, or the owning user.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The app","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"app":{"type":"object","properties":{"app_id":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client Application ID"},"app_name":{"type":"string","maxLength":128},"app_description":{"type":"string","maxLength":512},"created_at":{"type":"number","minimum":0},"public":{"type":"boolean"},"hardcoded":{"type":"boolean"},"web":{"type":"boolean"},"owner_type":{"type":"string","enum":["platform","organization","user","dynamic-client-registration"]},"owner_organization_id":{"type":["string","null"]},"owner_uid":{"type":["string","null"],"format":"uuid"},"created_by":{"type":["string","null"],"format":"uuid"},"client_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"logo_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"tos_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"policy_uri":{"type":["string","null"],"maxLength":2048,"format":"uri"},"contacts":{"type":["array","null"],"items":{"type":"string","maxLength":320},"maxItems":20},"grant_types":{"type":["array","null"],"items":{"type":"string","enum":["authorization_code","refresh_token"]}},"response_types":{"type":["array","null"],"items":{"type":"string","enum":["code"]}},"token_endpoint_auth_method":{"type":["string","null"],"enum":["none","client_secret_basic","client_secret_post",null]},"software_id":{"type":["string","null"],"maxLength":255},"software_version":{"type":["string","null"],"maxLength":255},"registered_scope":{"type":["string","null"],"maxLength":1024},"client_id_issued_at":{"type":["integer","null"],"minimum":0}},"required":["app_id","app_name","app_description","created_at","public","hardcoded","web"],"additionalProperties":false}},"required":["success","app"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"delete_api_apps_app_id","summary":"Delete a client application","description":"Organization owners, the owning user of a user-owned app, or platform administrators may delete an app (platform-owned apps: administrators only). Hardcoded apps cannot be deleted.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The app was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"The app could not be deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/check-authorization":{"get":{"operationId":"get_api_apps_app_id_check_authorization","summary":"Check whether the caller authorized an app","description":"Reports whether the signed-in user has already authorized the client application to receive tokens on their behalf. The auth server's own app is always reported as authorized.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The authorization status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppAuthorizationStatusResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to check the authorization status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/authorize":{"post":{"operationId":"post_api_apps_app_id_authorize","summary":"Authorize a client application","description":"Records the caller's consent for a client application to receive tokens on their behalf. Idempotent. The auth server's own app is always authorized and cannot be explicitly authorized (403). The JSON body is optional.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"requestBody":{"required":false,"description":"Optional; unknown fields are rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizeAppRequest"}}}},"responses":{"200":{"description":"The app is authorized for the caller","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to record the authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/domains":{"get":{"operationId":"get_api_apps_app_id_domains","summary":"List an app's domains","description":"Lists the domains registered for a client application per environment. Private apps are only visible to platform administrators, members of the owning organization, or the owning user.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The app's domains","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAppDomainsResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the domains","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_apps_app_id_domains","summary":"Add a domain to an app","description":"Registers a domain for a client application in one environment. Requires management access: platform administrators, owners / admins of the owning organization, or the owning user. The body's `app_id` must match the path.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaVaultsAppDomainRef"}}}},"responses":{"200":{"description":"The domain was added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The domain is already registered for this app and environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to add the domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/callback-urls":{"get":{"operationId":"get_api_apps_app_id_callback_urls","summary":"List an app's callback URLs","description":"Lists the explicit OAuth2 / OIDC callback (redirect) URLs registered for a client application. Visibility mirrors the domains listing: public apps, members of the owning organization, the owning user, and platform administrators.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The app's callback URLs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAppCallbackUrlsResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the callback URLs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_apps_app_id_callback_urls","summary":"Add a callback URL to an app","description":"Registers an explicit callback URL for a client application in one environment. Once at least one callback URL exists for an app + environment, `redirect_uri` validation for that environment requires an exact match against the registered list (instead of any path on a registered domain). Requires management access; hardcoded apps cannot be configured. The body's `app_id` must match the path.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchemaVaultsAppCallbackUrlRef"}}}},"responses":{"200":{"description":"The callback URL was added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The app is hardcoded, or the caller may not manage it (platform administrators, owners / admins of the owning organization, or the owning user only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The callback URL is already registered for this app and environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app or verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/callback-urls/{app_callback_url_ref_id}":{"delete":{"operationId":"delete_api_apps_app_id_callback_urls_app_callback_url_ref_id","summary":"Remove a callback URL from an app","description":"Removes a callback URL from a client application's explicit allowlist. When the last one for an environment is removed, `redirect_uri` validation for that environment falls back to origin matching against the app's domains. Requires management access; hardcoded apps cannot be configured.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"The callback URL reference id"},"required":true,"description":"The callback URL reference id","name":"app_callback_url_ref_id","in":"path"}],"responses":{"200":{"description":"The callback URL was removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The app is hardcoded, or the caller may not manage it (platform administrators, owners / admins of the owning organization, or the owning user only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app, or no callback URL with the given id for this app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app or verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/client-secret":{"get":{"operationId":"get_api_apps_app_id_client_secret","summary":"Get client secret metadata","description":"Reports whether a client application has a client secret (is a confidential client) and when it was generated / rotated. The secret itself is never retrievable after generation. Requires management access; hardcoded apps cannot be configured.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The client secret metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientSecretMetadataResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The app is hardcoded, or the caller may not manage it (platform administrators, owners / admins of the owning organization, or the owning user only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app or verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_apps_app_id_client_secret","summary":"Generate a client secret","description":"Generates a client secret for a client application that has none, making it a confidential OAuth2 / OIDC client. Returns the plaintext secret exactly once. Requires management access; hardcoded apps cannot be configured.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The new plaintext client secret (shown once)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientSecretGenerationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The app is hardcoded, or the caller may not manage it (platform administrators, owners / admins of the owning organization, or the owning user only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The app already has a client secret (POST only); rotate it instead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app or verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"operationId":"put_api_apps_app_id_client_secret","summary":"Rotate a client secret","description":"Rotates (or creates) the client secret of a client application on demand. The previous secret is invalidated immediately. Returns the new plaintext secret exactly once. Requires management access; hardcoded apps cannot be configured.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The new plaintext client secret (shown once)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientSecretGenerationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The app is hardcoded, or the caller may not manage it (platform administrators, owners / admins of the owning organization, or the owning user only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The app already has a client secret (POST only); rotate it instead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app or verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"delete_api_apps_app_id_client_secret","summary":"Remove a client secret","description":"Removes the client secret of a client application, reverting it to a public client. Requires management access; hardcoded apps cannot be configured.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The client secret was removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The app is hardcoded, or the caller may not manage it (platform administrators, owners / admins of the owning organization, or the owning user only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app, or the app has no client secret to remove","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app or verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apps/{app_id}/service-account":{"get":{"operationId":"get_api_apps_app_id_service_account","summary":"Get an app's service account","description":"Returns the client application's service account (the machine identity `grant_type=client_credentials` tokens are minted for), if any, and whether the app is currently a confidential client, i.e. eligible for that grant. Requires management access; hardcoded apps cannot be configured.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The service account (or null) and the app's client secret status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppServiceAccountResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The app is hardcoded, or the caller may not manage it (platform administrators, owners / admins of the owning organization, or the owning user only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app or verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_apps_app_id_service_account","summary":"Create an app's service account","description":"Creates the client application's service account ahead of its first client_credentials grant, so its uid can be granted permissions on resource servers up front. Idempotent: an existing service account is returned with `created: false` and status 200. Requires management access; hardcoded apps cannot be configured.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The app already had a service account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppServiceAccountCreationResponse"}}}},"201":{"description":"The service account was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppServiceAccountCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The app is hardcoded, or the caller may not manage it (platform administrators, owners / admins of the owning organization, or the owning user only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app or verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"delete_api_apps_app_id_service_account","summary":"Remove an app's service account","description":"Removes the client application's service account. Its issued-token records go with it; the next client_credentials grant creates a fresh identity with a new uid. Requires management access; hardcoded apps cannot be configured.","tags":["Client applications"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"app_id","in":"path"}],"responses":{"200":{"description":"The service account was removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The app is hardcoded, or the caller may not manage it (platform administrators, owners / admins of the owning organization, or the owning user only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app, or the app has no service account to remove","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the app or verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apis":{"get":{"operationId":"get_api_apis","summary":"List API servers","description":"Lists API server registrations. `list_apis_query_type` selects the scope: `all` (platform administrators only), `org` (members of the organization named by `organization_id`), `owned` (API servers owned by the caller's account) or `accessible` (every API server the caller can reach by ownership).","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"`all` requires a platform administrator; `org` requires membership of that organization."},"parameters":[{"schema":{"type":"string","description":"One of `all`, `org`, `owned`, `accessible` (required)","example":"accessible"},"required":false,"description":"One of `all`, `org`, `owned`, `accessible` (required)","name":"list_apis_query_type","in":"query"},{"schema":{"type":"string","description":"Organization whose API servers to list; required when `list_apis_query_type` is `org`","example":"my-organization"},"required":false,"description":"Organization whose API servers to list; required when `list_apis_query_type` is `org`","name":"organization_id","in":"query"}],"responses":{"200":{"description":"The API servers in the requested scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListApiServersResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list API servers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_apis","summary":"Register an API server","description":"Registers a new API server (resource server). The body's ownership fields decide who owns it: platform (administrators only), an organization the caller owns/administers, or the caller's own account (when user-owned resources are enabled). `hardcoded` must be false; `created_at`/`created_by` are set by the server.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Platform-owned API servers: administrators only. Organization-owned: organization owners/admins. User-owned: any user when the `allow_user_owned_resource_creation` setting is on."},"requestBody":{"required":true,"description":"The API server to register; `hardcoded` must be `false`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiServerDefinition"}}}},"responses":{"200":{"description":"The API server was registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"An API server with that id already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to register the API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apis/{api_server_id}":{"get":{"operationId":"get_api_apis_api_server_id","summary":"Get an API server","description":"Loads one API server registration. Private (not publicly listed) API servers are only visible to platform administrators, members of the owning organization, or the owning user.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"}],"responses":{"200":{"description":"The API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiServerResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"operationId":"patch_api_apis_api_server_id","summary":"Update an API server's dynamic-client policy","description":"Updates whether dynamically registered clients may request tokens for this API server as an RFC 8707 `resource`, and how a `resource` URL is matched against its registered domains. Nothing else about an API server is updatable here. Hardcoded API servers cannot be changed.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Organization owners/admins of the owning organization, the owning user, or platform administrators."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiServerDynamicClientPolicyUpdate"}}}},"responses":{"200":{"description":"The updated API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiServerResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to update the API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"delete_api_apis_api_server_id","summary":"Delete an API server","description":"Deletes an API server registration together with its domains, JWKS access keys and app connections. Hardcoded API servers cannot be deleted.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Organization owners of the owning organization, the owning user of a user-owned API server, or platform administrators (platform-owned API servers: administrators only)."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"}],"responses":{"200":{"description":"The API server was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apis/{api_server_id}/domains":{"get":{"operationId":"get_api_apis_api_server_id_domains","summary":"List an API server's domains","description":"Lists the domains registered for an API server across app environments.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Members (any role) of the owning organization, the owning user of a user-owned API server, or platform administrators."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"}],"responses":{"200":{"description":"The API server's domains","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListApiServerDomainsResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the domains","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_apis_api_server_id_domains","summary":"Add a domain to an API server","description":"Registers a domain for the API server in one app environment. The body's `api_server_id` must equal the path parameter. The same domain may be registered once per environment.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Organization owners/admins of the owning organization, the owning user of a user-owned API server, or platform administrators."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"}],"requestBody":{"required":true,"description":"The domain to register; `api_server_id` must match the path.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiServerDomainRef"}}}},"responses":{"200":{"description":"The domain was added; `resource_id` is the API server id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"That domain is already registered for this environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to add the domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apis/{api_server_id}/connect_app/{client_app_id}":{"get":{"operationId":"get_api_apis_api_server_id_connect_app_client_app_id","summary":"Check whether an app is connected to an API server","description":"Reports whether the client application is connected to the API server, i.e. may be issued access tokens with the API server as audience.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"The caller must own the client application (organization owner, owning user, or platform administrator) and, unless the API server is a public hardcoded one, must own the API server too."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"},{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"client_app_id","in":"path"}],"responses":{"200":{"description":"The connection status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppToApiServerConnectionResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app or API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to check the connection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_apis_api_server_id_connect_app_client_app_id","summary":"Connect an app to an API server","description":"Allows the client application to be issued access tokens for the API server. Responds 409 when the app is already connected (the client SDK maps it to `AppAlreadyConnectedToApiServerError`). No request body.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"The caller must own the client application (organization owner, owning user, or platform administrator) and, unless the API server is a public hardcoded one, must own the API server too."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"},{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"client_app_id","in":"path"}],"responses":{"200":{"description":"The app was connected; `resource_id` is the API server id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app or API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The app is already connected to the API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to connect the app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"delete_api_apis_api_server_id_connect_app_client_app_id","summary":"Disconnect an app from an API server","description":"Revokes the client application's connection to the API server so it can no longer be issued access tokens for it. Responds 404 when the app was not connected.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"The caller must own the client application (organization owner, owning user, or platform administrator) and, unless the API server is a public hardcoded one, must own the API server too."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"},{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Client application id","example":"my-web-app"},"required":true,"description":"Client application id","name":"client_app_id","in":"path"}],"responses":{"200":{"description":"The app was disconnected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such app, API server, or connection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to disconnect the app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/apis/{api_server_id}/jwks-access-key":{"get":{"operationId":"get_api_apis_api_server_id_jwks_access_key","summary":"Get JWKS access key metadata","description":"Reports the active JWKS access key of an API server (id, creation time, active flag) without the key material. `key_metadata` is `false` when no key has been generated yet.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Organization owners/admins of the owning organization, the owning user of a user-owned API server, or platform administrators. Refused for the auth server's own API server, which is the JWKS provider itself."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"}],"responses":{"200":{"description":"The key metadata, or `key_metadata: false`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JwksAccessKeyMetadataResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to verify authorization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_apis_api_server_id_jwks_access_key","summary":"Generate a JWKS access key","description":"Generates the initial JWKS access key pair of an API server and returns the private key once; the auth server keeps only the public key. Responds 409 when a key already exists (use `PUT` to rotate it). No request body.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Organization owners/admins of the owning organization, the owning user of a user-owned API server, or platform administrators. Refused for the auth server's own API server, which is the JWKS provider itself."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"}],"responses":{"200":{"description":"The new key pair; the private key is not retrievable later","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JwksAccessKeyGeneratedResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A JWKS access key already exists for this API server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to verify authorization or to generate the key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"operationId":"put_api_apis_api_server_id_jwks_access_key","summary":"Regenerate a JWKS access key","description":"Rotates an API server's JWKS access key: every previous key is deactivated and a new key pair is created, whose private key is returned once. Works whether or not a key existed before. No request body.","tags":["API servers"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Organization owners/admins of the owning organization, the owning user of a user-owned API server, or platform administrators. Refused for the auth server's own API server, which is the JWKS provider itself."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id","example":"my-resource-api"},"required":true,"description":"API server id","name":"api_server_id","in":"path"}],"responses":{"200":{"description":"The new key pair; the private key is not retrievable later","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JwksAccessKeyGeneratedResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to verify authorization or to regenerate the key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/organizations":{"post":{"operationId":"post_api_organizations","summary":"Create an organization","description":"Creates an organization and makes the caller its owner. When the `admin_only_organization_creation` server setting is on, only platform administrators may create organizations. Reserved (hardcoded) organization ids are refused.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null},"requestBody":{"required":true,"description":"`created_by` is ignored and set to the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationDefinition"}}}},"responses":{"200":{"description":"The organization was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The body failed validation or names a reserved id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The organization id is taken, or the caller reached the membership limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to create the organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"operationId":"get_api_organizations","summary":"List every organization","description":"Platform administrators only. Users list their own memberships with `GET /api/me/organizations`.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"responses":{"200":{"description":"All organizations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"organizations":{"type":"array","items":{"type":"object","properties":{"organization_id":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$"},"name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9]([a-zA-Z0-9 _-]*[a-zA-Z0-9])?$"},"created_at":{"type":"number","exclusiveMinimum":0},"created_by":{"type":["string","null"],"format":"uuid"}},"required":["organization_id","name","created_at"],"additionalProperties":false}}},"required":["organizations"]}},"required":["success","message","data"]}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list organizations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/organizations/{organization_id}":{"delete":{"operationId":"delete_api_organizations_organization_id","summary":"Delete an organization","description":"Deletes an organization together with its memberships and invitations. Only owners of the organization or platform administrators may delete it; system (hardcoded) organizations cannot be deleted.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Only organization owners or platform administrators may delete an organization."},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization id (URL-safe slug)","example":"acme-inc"},"required":true,"description":"Organization id (URL-safe slug)","name":"organization_id","in":"path"}],"responses":{"200":{"description":"The organization was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to delete the organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/organizations/{organization_id}/members":{"get":{"operationId":"get_api_organizations_organization_id_members","summary":"List an organization's members","description":"Lists every member of the organization with their role and account data. Members of the organization and platform administrators may call it.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"The caller must be a member of the organization or a platform administrator."},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization id (URL-safe slug)","example":"acme-inc"},"required":true,"description":"Organization id (URL-safe slug)","name":"organization_id","in":"path"}],"responses":{"200":{"description":"The organization's members","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationMember"}}},"required":["members"]}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/organizations/{organization_id}/members/{uid}/role":{"get":{"operationId":"get_api_organizations_organization_id_members_uid_role","summary":"Get a member's role","description":"Returns the role one user holds in the organization. Members of the organization and platform administrators may call it.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"The caller must be a member of the organization or a platform administrator."},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization id (URL-safe slug)","example":"acme-inc"},"required":true,"description":"Organization id (URL-safe slug)","name":"organization_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"User id of the member"},"required":true,"description":"User id of the member","name":"uid","in":"path"}],"responses":{"200":{"description":"The member's role","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"role":{"type":"string","description":"Membership role in the organization: `owner`, `member`, or `admin` (the virtual role platform administrators hold in the owner organization).","example":"member"}},"required":["role"]}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The user is not a member of the organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"operationId":"patch_api_organizations_organization_id_members_uid_role","summary":"Change a member's role","description":"Promotes a member to `owner` or demotes an owner to `member`. Only organization owners and platform administrators may change roles; the last owner cannot be demoted, the virtual `admin` role cannot be assigned, and roles in system organizations cannot be changed.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"The caller must be an owner of the organization or a platform administrator."},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization id (URL-safe slug)","example":"acme-inc"},"required":true,"description":"Organization id (URL-safe slug)","name":"organization_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"User id of the member"},"required":true,"description":"User id of the member","name":"uid","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganizationMemberRoleRequest"}}}},"responses":{"200":{"description":"The role was updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessageResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The user is not a member of the organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to update the role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/organizations/{organization_id}/invitations":{"get":{"operationId":"get_api_organizations_organization_id_invitations","summary":"List an organization's invitations","description":"Lists every invitation of the organization (pending, accepted, declined, revoked and expired) with the inviter's and invitee's e-mail addresses. Organization owners and platform administrators only.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Only organization owners or platform administrators may list invitations."},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization id (URL-safe slug)","example":"acme-inc"},"required":true,"description":"Organization id (URL-safe slug)","name":"organization_id","in":"path"}],"responses":{"200":{"description":"The organization's invitations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"invitations":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationInvitationListEntry"}}},"required":["invitations"]}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the invitations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_organizations_organization_id_invitations","summary":"Invite a user to an organization","description":"Creates a pending invitation for an existing user (looked up by e-mail address or user id) and e-mails them. Organization owners and platform administrators only. Refused when the user is already a member or already has a pending invitation.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Only organization owners or platform administrators may invite members."},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization id (URL-safe slug)","example":"acme-inc"},"required":true,"description":"Organization id (URL-safe slug)","name":"organization_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationInvitationRequest"}}}},"responses":{"201":{"description":"The invitation was created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"invitation":{"$ref":"#/components/schemas/OrganizationInvitation"}},"required":["invitation"]}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No user matches the identifier","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The user is already a member, or already has a pending invitation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to create the invitation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/organizations/{organization_id}/invitations/{invitation_id}":{"patch":{"operationId":"patch_api_organizations_organization_id_invitations_invitation_id","summary":"Accept or decline an invitation","description":"Lets the invited user accept (joining the organization as a member) or decline a pending invitation. Only the invitee may respond; accepting is refused once the caller reached the membership limit.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Only the invited user may respond to an invitation."},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization id (URL-safe slug)","example":"acme-inc"},"required":true,"description":"Organization id (URL-safe slug)","name":"organization_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Id of the invitation"},"required":true,"description":"Id of the invitation","name":"invitation_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RespondToOrganizationInvitationRequest"}}}},"responses":{"200":{"description":"The invitation was accepted or declined","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"invitation":{"$ref":"#/components/schemas/OrganizationInvitation"}}}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such invitation in this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The caller reached the organization membership limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to respond to the invitation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"delete_api_organizations_organization_id_invitations_invitation_id","summary":"Revoke an invitation","description":"Revokes a pending invitation so it can no longer be accepted. Organization owners and platform administrators only; invitations that are no longer pending cannot be revoked.","tags":["Organizations"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"Only organization owners or platform administrators may revoke invitations."},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization id (URL-safe slug)","example":"acme-inc"},"required":true,"description":"Organization id (URL-safe slug)","name":"organization_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"Id of the invitation"},"required":true,"description":"Id of the invitation","name":"invitation_id","in":"path"}],"responses":{"200":{"description":"The invitation was revoked","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"invitation":{"$ref":"#/components/schemas/OrganizationInvitation"}}}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The account is disabled, or the credential is valid but not allowed to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such invitation in this organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to revoke the invitation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/users/list":{"get":{"operationId":"get_api_admin_users_list","summary":"List every user","description":"Lists every registered account (humans and service accounts) with its verification, admin and disabled flags and profile fields.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"responses":{"200":{"description":"All users","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserRecord"}}},"required":["users"]}},"required":["success","message","data"]}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/users/{uid}":{"delete":{"operationId":"delete_api_admin_users_uid","summary":"Delete a user","description":"Permanently deletes a user account. Organizations whose only remaining member was this user are deleted with it (cascading to their apps, API servers, memberships and invitations). Administrators cannot delete their own account here.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"uid of the user to delete"},"required":true,"description":"uid of the user to delete","name":"uid","in":"path"}],"responses":{"200":{"description":"The user was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to delete the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/users/{uid}/disable":{"post":{"operationId":"post_api_admin_users_uid_disable","summary":"Disable a user","description":"Marks the account disabled and revokes every session and token it holds (the user's `tokens_valid_after` watermark is pinned while the account stays disabled), so it can no longer log in or use an existing session. Administrators cannot disable themselves.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"uid of the target user"},"required":true,"description":"uid of the target user","name":"uid","in":"path"}],"responses":{"200":{"description":"The user's disabled state was updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to update the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"delete_api_admin_users_uid_disable","summary":"Re-enable a user","description":"Clears the disabled flag set by `POST /api/admin/users/{uid}/disable`. Sessions revoked by the disable stay revoked: the user has to log in again.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"uid of the target user"},"required":true,"description":"uid of the target user","name":"uid","in":"path"}],"responses":{"200":{"description":"The user's disabled state was updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to update the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/users/{uid}/mfa":{"get":{"operationId":"get_api_admin_users_uid_mfa","summary":"List a user's MFA factor types","description":"Reports which kinds of verified second factors (TOTP, passkeys) the user has enrolled.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"uid of the target user"},"required":true,"description":"uid of the target user","name":"uid","in":"path"}],"responses":{"200":{"description":"The user's verified factor types","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"factor_types":{"type":"array","items":{"type":"string","enum":["totp","webauthn"]}}},"required":["factor_types"]}},"required":["success","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the user's factors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"delete_api_admin_users_uid_mfa","summary":"Reset a user's MFA","description":"Removes every second factor and recovery code of the user, so they log in with their password alone until they enroll again. The user is notified by e-mail.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"uid of the target user"},"required":true,"description":"uid of the target user","name":"uid","in":"path"}],"responses":{"200":{"description":"All factors were removed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to reset the user's MFA","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/users/{uid}/resend-verification":{"post":{"operationId":"post_api_admin_users_uid_resend_verification","summary":"Resend a user's verification e-mail","description":"Issues a fresh e-mail verification token for the user and e-mails the verification link to them.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"uid of the target user"},"required":true,"description":"uid of the target user","name":"uid","in":"path"}],"responses":{"200":{"description":"The verification e-mail was sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The user's e-mail address is already verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to load the user or send the e-mail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/users/{uid}/tokens":{"get":{"operationId":"get_api_admin_users_uid_tokens","summary":"List a user's issued tokens","description":"Lists the most recent 200 access / refresh tokens recorded for the user in the issued-tokens audit table, optionally filtered by kind.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"uid of the target user"},"required":true,"description":"uid of the target user","name":"uid","in":"path"},{"schema":{"type":"string","enum":["access","refresh"],"description":"Only list tokens of this kind"},"required":false,"description":"Only list tokens of this kind","name":"token_type","in":"query"}],"responses":{"200":{"description":"The user's issued tokens","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/AdminIssuedToken"}}},"required":["tokens"]}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list the tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/promote/{uid}":{"post":{"operationId":"post_api_admin_promote_uid","summary":"Promote a user to administrator","description":"Grants the platform administrator flag to the user with the given uid.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"uid of the user to promote"},"required":true,"description":"uid of the user to promote","name":"uid","in":"path"}],"responses":{"200":{"description":"The user is now an administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to promote the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/invite-codes":{"get":{"operationId":"get_api_admin_invite_codes","summary":"List invite codes","description":"Lists every registration invite code with its usage limit and creator.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"responses":{"200":{"description":"All invite codes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"invite_codes":{"type":"array","items":{"$ref":"#/components/schemas/InviteCodeDefinition"}}},"required":["invite_codes"]}},"required":["success","message","data"]}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list invite codes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"post_api_admin_invite_codes","summary":"Create an invite code","description":"Registers a new invite code. `created_at` must be within 30 seconds of the server clock (a stale definition is refused with 412) and `created_by` is overwritten with the caller's uid.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"requestBody":{"required":true,"description":"The invite code definition; `created_by` is ignored and set to the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteCodeDefinition"}}}},"responses":{"200":{"description":"The invite code was created; `resource_id` is the code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"An invite code with that value already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"412":{"description":"`created_at` is too far from the server clock","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to store the invite code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/invite-codes/{invite_code}/usages":{"get":{"operationId":"get_api_admin_invite_codes_invite_code_usages","summary":"Count invite code usages","description":"Returns how many accounts registered with the given invite code.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":8,"maxLength":64,"pattern":"^[A-Za-z0-9_-]+$","description":"The invite code","example":"WELCOME-2025"},"required":true,"description":"The invite code","name":"invite_code","in":"path"}],"responses":{"200":{"description":"The usage count","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"invite_code":{"type":"string"},"usage_count":{"type":"integer","minimum":0}},"required":["invite_code","usage_count"]}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to count usages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/settings":{"get":{"operationId":"get_api_admin_settings","summary":"List server settings","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"responses":{"200":{"description":"Every server setting with its current value","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"settings":{"type":"array","items":{"$ref":"#/components/schemas/ServerSettingRecord"}}},"required":["settings"]}},"required":["success","data"]}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list server settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/settings/{key}":{"patch":{"operationId":"patch_api_admin_settings_key","summary":"Update a server setting","description":"Sets the value of one server setting. The value is validated against the setting's own schema (boolean, string, ...).","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","example":"invite_codes_required"},"required":true,"name":"key","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateServerSettingRequest"}}}},"responses":{"200":{"description":"The updated setting","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"key":{"type":"string"},"value":{}},"required":["key"]}},"required":["success","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to update the setting","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/branding":{"get":{"operationId":"get_api_admin_branding","summary":"List branding asset slots","description":"Lists every white-label branding asset slot (favicon, app icon, ...) with its upload constraints and, when an administrator uploaded a custom asset, its metadata. The assets themselves are served publicly at `/branding/{asset}`.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"responses":{"200":{"description":"Every branding asset slot","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"assets":{"type":"array","items":{"$ref":"#/components/schemas/BrandingAssetMetadataRecord"}}},"required":["assets"]}},"required":["success","data"]}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list branding assets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/branding/{asset}":{"put":{"operationId":"put_api_admin_branding_asset","summary":"Upload a branding asset","description":"Replaces the image of one branding asset slot. The request body is the raw image bytes and the `Content-Type` header must be one of the slot's allowed MIME types (see `GET /api/admin/branding`); uploads above the slot's size limit are refused. The new asset is served immediately at `/branding/{asset}`.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","enum":["favicon","icon","opengraph-image"],"description":"Branding asset slot","example":"favicon"},"required":true,"description":"Branding asset slot","name":"asset","in":"path"}],"requestBody":{"required":true,"description":"The raw image bytes. Accepted image types depend on the slot (e.g. image/png, image/svg+xml, image/x-icon for the favicon); the request `Content-Type` header must name the image's MIME type.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary","description":"Raw image bytes; send the image's own MIME type as the request Content-Type"}}}},"responses":{"200":{"description":"The asset was stored","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/BrandingAssetUploadResult"}},"required":["success","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"The declared Content-Length exceeds the slot's size limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to store the asset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"delete_api_admin_branding_asset","summary":"Remove a custom branding asset","description":"Deletes the uploaded image of one branding asset slot so the deployment's default is served again.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","enum":["favicon","icon","opengraph-image"],"description":"Branding asset slot","example":"favicon"},"required":true,"description":"Branding asset slot","name":"asset","in":"path"}],"responses":{"200":{"description":"The slot was reverted to its default","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"key":{"type":"string"}},"required":["key"]}},"required":["success","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to remove the asset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/errors":{"delete":{"operationId":"delete_api_admin_errors","summary":"Delete captured errors before a cutoff","description":"Bulk-deletes rows of the captured server errors table older than the `before` cutoff. `resource_id` carries the number of deleted rows. A cutoff of `0` is valid and deletes nothing.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Cutoff: errors captured before this instant are deleted. An ISO-8601 datetime or a non-negative integer Unix epoch in milliseconds.","example":"2025-01-01T00:00:00Z"},"required":true,"description":"Cutoff: errors captured before this instant are deleted. An ISO-8601 datetime or a non-negative integer Unix epoch in milliseconds.","name":"before","in":"query"}],"responses":{"200":{"description":"The errors were deleted; `resource_id` is the deleted row count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to delete errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/errors/{error_id}":{"delete":{"operationId":"delete_api_admin_errors_error_id","summary":"Delete a captured error","description":"Removes one row of the captured server errors table.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","format":"uuid","description":"Id of the captured error"},"required":true,"description":"Id of the captured error","name":"error_id","in":"path"}],"responses":{"200":{"description":"The error was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreationResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to delete the error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/server-traces":{"get":{"operationId":"get_api_admin_server_traces","summary":"List recent server traces","description":"Returns the most recent timing traces (database queries, HTTP calls, subroutines) captured by the server, newest first: 200 by default, up to 5000 with `limit`. `since`, `op_name` and `op_category` narrow the listing before the limit applies.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":1,"description":"How many of the most recent matching traces to return (1–5000, default 200).","example":"1000"},"required":false,"description":"How many of the most recent matching traces to return (1–5000, default 200).","name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Only traces that started at or after this instant (a non-negative integer Unix epoch in milliseconds).","example":"1735689600000"},"required":false,"description":"Only traces that started at or after this instant (a non-negative integer Unix epoch in milliseconds).","name":"since","in":"query"},{"schema":{"anyOf":[{"type":"string","minLength":1},{"type":"array","items":{"type":"string","minLength":1},"maxItems":100}],"description":"Only traces of this operation. Repeat the parameter to keep several operations.","example":"POST /api/auth/login"},"required":false,"description":"Only traces of this operation. Repeat the parameter to keep several operations.","name":"op_name","in":"query"},{"schema":{"anyOf":[{"type":"string","enum":["database_query","http_response","http_request","subroutine"]},{"type":"array","items":{"type":"string","enum":["database_query","http_response","http_request","subroutine"]},"maxItems":4}],"description":"Only traces of this category. Repeat the parameter to keep several categories.","example":"subroutine"},"required":false,"description":"Only traces of this category. Repeat the parameter to keep several categories.","name":"op_category","in":"query"}],"responses":{"200":{"description":"The most recent matching traces","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"traces":{"type":"array","items":{"$ref":"#/components/schemas/AdminServerTrace"}}},"required":["traces"]}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list server traces","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/server-traces/operations":{"get":{"operationId":"get_api_admin_server_traces_operations","summary":"List traced operations","description":"Returns every operation that recorded a server trace (optionally only since `since`) with its category and trace count, busiest first. Use the names to filter `GET /api/admin/server-traces`.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Only traces that started at or after this instant (a non-negative integer Unix epoch in milliseconds).","example":"1735689600000"},"required":false,"description":"Only traces that started at or after this instant (a non-negative integer Unix epoch in milliseconds).","name":"since","in":"query"}],"responses":{"200":{"description":"The traced operations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"data":{"type":"object","properties":{"operations":{"type":"array","items":{"$ref":"#/components/schemas/AdminServerTraceOperation"}}},"required":["operations"]}},"required":["success","message","data"]}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to list traced operations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/admin/send-daily-report":{"get":{"operationId":"get_api_admin_send_daily_report","summary":"Send the daily admin report","description":"Builds the last 24 hours' activity report (new users, organizations, captured errors, most active users, most popular apps and APIs) and e-mails it to the administrator mailing list. Both GET and POST trigger it so it can be wired to simple cron schedulers.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null,"notes":"Scheduled jobs may call this without a session by sending the deployment's cron secret as `Authorization: Bearer <CRON_SECRET>`; that check runs before the session guard (see the route's cron bypass middleware). Every other caller needs an administrator session."},"responses":{"200":{"description":"The report was generated and sent; the body counts what it contained","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyAdminReportResult"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The report could not be generated or sent (note the `ok: false` envelope)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyAdminReportFailure"}}}}}},"post":{"operationId":"post_api_admin_send_daily_report","summary":"Send the daily admin report (POST)","description":"Builds the last 24 hours' activity report (new users, organizations, captured errors, most active users, most popular apps and APIs) and e-mails it to the administrator mailing list. Both GET and POST trigger it so it can be wired to simple cron schedulers.","tags":["Administration"],"security":[{"schemavaults-refresh-token-cookie":[]},{"schemavaults-access-token-cookie":[]},{"schemavaults-access-token":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-refresh-token-cookie","schemavaults-access-token-cookie","schemavaults-access-token"],"routeGuard":"admin","requiredScopes":[],"organization":null,"notes":"Scheduled jobs may call this without a session by sending the deployment's cron secret as `Authorization: Bearer <CRON_SECRET>`; that check runs before the session guard (see the route's cron bypass middleware). Every other caller needs an administrator session."},"responses":{"200":{"description":"The report was generated and sent; the body counts what it contained","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyAdminReportResult"}}}},"401":{"description":"No valid session cookie, access token cookie or bearer access token was presented, or the token was revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The caller is not a platform administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The report could not be generated or sent (note the `ok: false` envelope)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyAdminReportFailure"}}}}}}},"/api/jwks/{audience}":{"get":{"operationId":"get_api_jwks_audience","summary":"Load an API server's JWKS","description":"Returns the JSON Web Key Set the auth server signs and encrypts tokens for the given API server (`audience`) with, creating the keyset on first use. The set includes the private JWE decryption key, so only that API server may fetch it: it presents a single-use JWKS access assertion signed with its JWKS access private key (see `POST /api/apis/{api_server_id}/jwks-access-key`); resource servers built on `@schemavaults/auth-server-sdk` do this through `RemoteJwtKeyManager`. The auth server's own keys and the reserved `oidc-userinfo` keys are never exported here; the public verification keys are served unauthenticated at `GET /api/oidc/jwks`.","tags":["Resource servers"],"security":[{"schemavaults-jwks-access-assertion":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-jwks-access-assertion"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"The assertion's `iss` / `sub` must equal the `audience` path parameter, so an API server can only load its own JWKS. Every assertion is accepted once."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id whose JWKS to load; must equal the assertion's issuer","example":"my-resource-api"},"required":true,"description":"API server id whose JWKS to load; must equal the assertion's issuer","name":"audience","in":"path"}],"responses":{"200":{"description":"The JWKS of the audience, including the private JWE decryption key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonWebKeySet"}}}},"400":{"description":"The API server the assertion must be signed for (path parameter or `X-Api-Server-Id` header) is missing, malformed, or names the auth server itself; or the request failed validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceServerBadRequestResponse"}}}},"401":{"description":"No `Authorization: Bearer <assertion>` header was sent, or the assertion is malformed, expired, issued for another API server, not signed with the API server's active JWKS access key, or has already been used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The keyset could not be created or loaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceServerErrorResponse"}}}}}}},"/api/resource-server/apis/{api_server_id}/allowed-origins":{"get":{"operationId":"get_api_resource_server_apis_api_server_id_allowed_origins","summary":"List a resource server's allowed CORS origins","description":"Returns the origins a resource server should accept cross-origin requests from: the union of the domains, in this deployment's app environment, of every client application connected to the API server. The response is sent with `Cache-Control: no-store`. Resource servers built on `@schemavaults/auth-server-sdk` call this through `RemoteAllowedOriginsResolver`.","tags":["Resource servers"],"security":[{"schemavaults-jwks-access-assertion":[]}],"x-schemavaults-auth":{"public":false,"schemes":["schemavaults-jwks-access-assertion"],"routeGuard":"authenticated","requiredScopes":[],"organization":null,"notes":"The assertion's `iss` / `sub` must equal the `api_server_id` path parameter, so a resource server can only query its own allowed origins. Every assertion is accepted once."},"parameters":[{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"API server id; must equal the assertion's issuer","example":"my-resource-api"},"required":true,"description":"API server id; must equal the assertion's issuer","name":"api_server_id","in":"path"}],"responses":{"200":{"description":"The allowed origins","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceServerAllowedOriginsResponse"}}}},"400":{"description":"The API server the assertion must be signed for (path parameter or `X-Api-Server-Id` header) is missing, malformed, or names the auth server itself; or the request failed validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceServerBadRequestResponse"}}}},"401":{"description":"No `Authorization: Bearer <assertion>` header was sent, or the assertion is malformed, expired, issued for another API server, not signed with the API server's active JWKS access key, or has already been used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Failed to collect the origins","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceServerErrorResponse"}}}}}}},"/api/resource-server/organizations/{organization_id}/members/{uid}/role":{"get":{"operationId":"get_api_resource_server_organizations_organization_id_members_uid_role","summary":"Look up a user's organization role","description":"Tells a resource server which role (`owner`, `member`, ...) a user holds in an organization, or null when they are not a member or do not exist. Only the API server that the organization owns may ask about it: the calling API server names itself in the `X-Api-Server-Id` header and proves it with a single-use JWKS access assertion signed with its JWKS access private key. Resource servers built on `@schemavaults/auth-server-sdk` call this through `isUserInOrganization()`.","tags":["Resource servers"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null,"notes":"Requires `Authorization: Bearer <JWKS access assertion>` (the `schemavaults-jwks-access-assertion` scheme) signed by the API server named in `X-Api-Server-Id`; the handler verifies it after the path and header validation, so a malformed request is refused with 400 before the credential is examined, a missing or invalid assertion with 401. The API server must belong to `organization_id` (403 otherwise)."},"parameters":[{"schema":{"type":"string","minLength":4,"maxLength":32,"pattern":"^[a-z][a-z0-9_-]+$","description":"Organization the API server belongs to","example":"acme"},"required":true,"description":"Organization the API server belongs to","name":"organization_id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"User id to look up"},"required":true,"description":"User id to look up","name":"uid","in":"path"},{"schema":{"type":"string","minLength":2,"maxLength":64,"pattern":"^[a-z0-9_-]*$","description":"Id of the calling API server; the assertion must be signed with its JWKS access key","example":"my-resource-api"},"required":true,"description":"Id of the calling API server; the assertion must be signed with its JWKS access key","name":"x-api-server-id","in":"header"}],"responses":{"200":{"description":"The user's role (null when not a member)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationMemberRoleResponse"}}}},"400":{"description":"The request failed validation (`issues` lists the offending fields) or was refused by the handler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestResponse"}}}},"401":{"description":"No `Authorization: Bearer <assertion>` header, or the assertion did not verify for the API server named in `X-Api-Server-Id`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceServerErrorResponse"}}}},"403":{"description":"The API server does not belong to the organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceServerErrorResponse"}}}},"500":{"description":"Failed to look up the API server or the membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceServerErrorResponse"}}}}}}},"/api/environment":{"get":{"operationId":"get_api_environment","summary":"Deployment environment","description":"Reports which app environment this auth server runs in.","tags":["Configuration"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null},"responses":{"200":{"description":"The app environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}}}}},"/api/config/branding":{"get":{"operationId":"get_api_config_branding","summary":"White-label branding","description":"The deployment's friendly name and theme gradient colors, resolved from the `SCHEMAVAULTS_AUTH_SERVER_FRIENDLY_NAME` / `SCHEMAVAULTS_AUTH_SERVER_THEME_COLOR_1|2` environment variables. Public. Reads no database or cache, so it keeps answering while the rest of the server is failing; the global error page uses it to stay on-brand.","tags":["Configuration"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null},"responses":{"200":{"description":"The branding configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandingConfigResponse"}}}}}}},"/api/config/invite_code_required":{"get":{"operationId":"get_api_config_invite_code_required","summary":"Invite code policy","description":"Whether registering an account on this auth server requires an invite code (the `invite_codes_required` server setting). Public; the registration form uses it to decide whether to ask for a code.","tags":["Configuration"],"security":[],"x-schemavaults-auth":{"public":true,"schemes":[],"routeGuard":null,"requiredScopes":[],"organization":null},"responses":{"200":{"description":"The current policy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteCodeRequiredResponse"}}}},"500":{"description":"The server setting could not be loaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigurationErrorResponse"}}}}}}}},"webhooks":{}}