@faable/auth-sdk 2.7.89 → 2.7.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/spec/openapi.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "info": {
4
4
  "title": "@faablecloud/auth",
5
5
  "description": "Auth Platform made by Faable. Manage Users and Roles",
6
- "version": "2.69.2",
6
+ "version": "2.73.0",
7
7
  "license": {
8
8
  "name": "private",
9
9
  "url": "https://faable.com/docs/platform/privacy-policy"
@@ -536,6 +536,10 @@
536
536
  "type": "boolean",
537
537
  "description": "When true, anyone can register a client with `POST /oidc/register` (OIDC Dynamic Client Registration / RFC 7591) and the discovery document advertises `registration_endpoint`. Off by default: an open registration lets anyone create a client with their own `redirect_uri`."
538
538
  },
539
+ "client_id_metadata_documents_enabled": {
540
+ "type": "boolean",
541
+ "description": "When true, /authorize accepts a `client_id` that is an https URL serving a Client ID Metadata Document (the MCP authorization way to identify a client without registering it). Such clients always see the consent screen. Off by default."
542
+ },
539
543
  "canonical_host": {
540
544
  "type": "string",
541
545
  "description": "The one host this tenant's OIDC issuer and discovery document are always minted with, regardless of which host actually served the request — must be the account's own platform host or one of its verified custom domains. `/authorize` and `/logout` 302 here from any other host of the tenant. Unset (the default): every URL uses whatever host served the request, as before this field existed. Changing it can invalidate every WebAuthn passkey already enrolled unless `webauthn_rp_id` already covers the new host.",
@@ -1537,6 +1541,17 @@
1537
1541
  "token_endpoint_auth_method": {
1538
1542
  "type": "string"
1539
1543
  },
1544
+ "consent_required": {
1545
+ "type": "boolean",
1546
+ "description": "When true, /authorize never issues a code in silence for this client: the End-User approves it on the consent screen first. Set on clients the tenant did not create (Client ID Metadata Documents, dynamic registration)."
1547
+ },
1548
+ "metadata_document_url": {
1549
+ "type": "string",
1550
+ "description": "For a client identified by a Client ID Metadata Document: the URL (also its client_id) its metadata was fetched from."
1551
+ },
1552
+ "registered_dynamically": {
1553
+ "type": "boolean"
1554
+ },
1540
1555
  "application_type": {
1541
1556
  "type": "string"
1542
1557
  },
@@ -4136,6 +4151,55 @@
4136
4151
  "type": "boolean",
4137
4152
  "description": "When true, the API is eligible to be the target of a `refresh_token` (i.e. clients can request `offline_access` against it)."
4138
4153
  },
4154
+ "consent_options": {
4155
+ "type": "object",
4156
+ "required": [
4157
+ "claim",
4158
+ "label",
4159
+ "url",
4160
+ "audience"
4161
+ ],
4162
+ "properties": {
4163
+ "claim": {
4164
+ "type": "string",
4165
+ "pattern": "^[a-z][a-z0-9_]{0,31}$",
4166
+ "description": "Access token claim that carries the chosen id."
4167
+ },
4168
+ "label": {
4169
+ "type": "string",
4170
+ "maxLength": 60,
4171
+ "description": "What the screen asks for, e.g. \"Project\"."
4172
+ },
4173
+ "url": {
4174
+ "type": "string",
4175
+ "pattern": "^https://",
4176
+ "description": "GET endpoint of the resource server that lists the choices."
4177
+ },
4178
+ "audience": {
4179
+ "type": "string",
4180
+ "description": "Identifier of a registered API the listing token is issued for (usually the resource server behind `url`)."
4181
+ }
4182
+ },
4183
+ "nullable": true
4184
+ },
4185
+ "delegation": {
4186
+ "type": "object",
4187
+ "required": [
4188
+ "client_id",
4189
+ "audience"
4190
+ ],
4191
+ "properties": {
4192
+ "client_id": {
4193
+ "type": "string",
4194
+ "description": "The confidential client of the resource server allowed to exchange."
4195
+ },
4196
+ "audience": {
4197
+ "type": "string",
4198
+ "description": "Identifier of the registered API the new token is for."
4199
+ }
4200
+ },
4201
+ "nullable": true
4202
+ },
4139
4203
  "skip_consent": {
4140
4204
  "type": "boolean",
4141
4205
  "description": "When true, the consent prompt is skipped for first-party clients (clients owned by the same tenant as the API)."
@@ -4256,6 +4320,53 @@
4256
4320
  "type": "boolean",
4257
4321
  "description": "When true, clients can request `offline_access` and receive a refresh_token for this API."
4258
4322
  },
4323
+ "consent_options": {
4324
+ "type": "object",
4325
+ "required": [
4326
+ "claim",
4327
+ "label",
4328
+ "url",
4329
+ "audience"
4330
+ ],
4331
+ "properties": {
4332
+ "claim": {
4333
+ "type": "string",
4334
+ "pattern": "^[a-z][a-z0-9_]{0,31}$",
4335
+ "description": "Access token claim that carries the chosen id."
4336
+ },
4337
+ "label": {
4338
+ "type": "string",
4339
+ "maxLength": 60,
4340
+ "description": "What the screen asks for, e.g. \"Project\"."
4341
+ },
4342
+ "url": {
4343
+ "type": "string",
4344
+ "pattern": "^https://",
4345
+ "description": "GET endpoint of the resource server that lists the choices."
4346
+ },
4347
+ "audience": {
4348
+ "type": "string",
4349
+ "description": "Identifier of a registered API the listing token is issued for (usually the resource server behind `url`)."
4350
+ }
4351
+ }
4352
+ },
4353
+ "delegation": {
4354
+ "type": "object",
4355
+ "required": [
4356
+ "client_id",
4357
+ "audience"
4358
+ ],
4359
+ "properties": {
4360
+ "client_id": {
4361
+ "type": "string",
4362
+ "description": "The confidential client of the resource server allowed to exchange."
4363
+ },
4364
+ "audience": {
4365
+ "type": "string",
4366
+ "description": "Identifier of the registered API the new token is for."
4367
+ }
4368
+ }
4369
+ },
4259
4370
  "skip_consent": {
4260
4371
  "type": "boolean",
4261
4372
  "description": "When true, skip the consent prompt for first-party clients."
@@ -4340,6 +4451,55 @@
4340
4451
  "type": "boolean",
4341
4452
  "description": "When true, clients can request `offline_access` and receive a refresh_token for this API."
4342
4453
  },
4454
+ "consent_options": {
4455
+ "type": "object",
4456
+ "required": [
4457
+ "claim",
4458
+ "label",
4459
+ "url",
4460
+ "audience"
4461
+ ],
4462
+ "properties": {
4463
+ "claim": {
4464
+ "type": "string",
4465
+ "pattern": "^[a-z][a-z0-9_]{0,31}$",
4466
+ "description": "Access token claim that carries the chosen id."
4467
+ },
4468
+ "label": {
4469
+ "type": "string",
4470
+ "maxLength": 60,
4471
+ "description": "What the screen asks for, e.g. \"Project\"."
4472
+ },
4473
+ "url": {
4474
+ "type": "string",
4475
+ "pattern": "^https://",
4476
+ "description": "GET endpoint of the resource server that lists the choices."
4477
+ },
4478
+ "audience": {
4479
+ "type": "string",
4480
+ "description": "Identifier of a registered API the listing token is issued for (usually the resource server behind `url`)."
4481
+ }
4482
+ },
4483
+ "nullable": true
4484
+ },
4485
+ "delegation": {
4486
+ "type": "object",
4487
+ "required": [
4488
+ "client_id",
4489
+ "audience"
4490
+ ],
4491
+ "properties": {
4492
+ "client_id": {
4493
+ "type": "string",
4494
+ "description": "The confidential client of the resource server allowed to exchange."
4495
+ },
4496
+ "audience": {
4497
+ "type": "string",
4498
+ "description": "Identifier of the registered API the new token is for."
4499
+ }
4500
+ },
4501
+ "nullable": true
4502
+ },
4343
4503
  "skip_consent": {
4344
4504
  "type": "boolean",
4345
4505
  "description": "When true, skip the consent prompt for first-party clients."
@@ -6779,7 +6939,6 @@
6779
6939
  "type": "object",
6780
6940
  "required": [
6781
6941
  "client_id",
6782
- "client_secret",
6783
6942
  "client_id_issued_at",
6784
6943
  "client_secret_expires_at",
6785
6944
  "redirect_uris",
@@ -7523,6 +7682,10 @@
7523
7682
  "type": "boolean",
7524
7683
  "nullable": true
7525
7684
  },
7685
+ "client_id_metadata_documents_enabled": {
7686
+ "type": "boolean",
7687
+ "nullable": true
7688
+ },
7526
7689
  "canonical_host": {
7527
7690
  "type": "string",
7528
7691
  "nullable": true
@@ -7858,7 +8021,7 @@
7858
8021
  },
7859
8022
  "ErrorCode": {
7860
8023
  "type": "string",
7861
- "description": "Machine-readable error code. One HTTP status per code.\n\n- `bad_request` (400): The request is malformed. `message` says what is wrong.\n- `validation_error` (400): The body, query or path failed schema validation. `details.issues` lists each failing field.\n- `unauthorized` (401): The request carries no valid credentials.\n- `payment_required` (402): The feature is not included in the current plan.\n- `forbidden` (403): The credentials are valid but do not allow this operation.\n- `not_found` (404): The resource does not exist in this account.\n- `method_not_allowed` (405): The HTTP method is not supported on this path.\n- `conflict` (409): The request conflicts with the current state of the resource.\n- `payload_too_large` (413): The request body exceeds the size limit.\n- `unsupported_media_type` (415): The `Content-Type` is not accepted by this endpoint.\n- `unprocessable_entity` (422): The request is well-formed but cannot be processed.\n- `too_many_requests` (429): Rate limit exceeded. Honour the `Retry-After` header.\n- `internal_error` (500): Unexpected server error. Retry later; the request id is logged.\n- `already_exists` (400): A resource with the same unique field already exists (for a user, usually `email`). `details.fields` names the field.\n- `invalid_id` (400): The id in the path is not a valid id for this resource.\n- `account_not_found` (404): No Auth Account matches the request (domain, header or token).\n- `invalid_query` (400): The `?query=` FaableQL expression could not be parsed.\n- `search_not_supported` (400): This resource does not support `?search=`.\n- `invalid_expand` (400): An `?expand=` path is not allowed on this resource.\n- `access_denied` (401): The caller may not access this row (ownership or machine-to-machine restriction).\n- `insufficient_scope` (403): The token lacks a scope this operation requires. `message` names it.\n- `team_required` (400): An Auth Account must belong to a project (team).\n- `account_limit_reached` (409): The project already has the maximum number of Auth Accounts.\n- `invalid_project_id` (400): The project id is not of the form `project_<hex>` or `team_<hex>`.\n- `account_transfer_refused` (409): The Auth Account cannot be moved to that project. `details.blockers` lists why.\n- `email_sender_domain_not_allowed` (400): The sender address is not in a domain this platform signs email for (AUTH_EMAIL_SENDER_DOMAINS).\n- `plan_required` (402): The setting requires a higher plan. `message` says which.\n- `invalid_canonical_host` (400): `canonical_host` must be this account's own platform host or one of its verified custom domains.\n- `canonical_host_breaks_passkeys` (400): `canonical_host` is outside the account's current WebAuthn RP ID — every passkey already enrolled would stop working. Set `webauthn_rp_id` in the same request to a suffix that covers both.\n- `not_logged_in` (401): There is no signed-in session for this request.\n- `session_already_revoked` (409): The session was already revoked.\n- `invalid_token` (401): The bearer token is missing, malformed, expired or has no subject.\n- `not_owner` (403): The caller may only perform this operation on their own user.\n- `user_suspended` (403): The user is suspended and cannot sign in or be modified.\n- `invalid_credentials` (400): The email/username or password is incorrect.\n- `login_denied` (401): A post-login Action denied the sign-in. `message` carries the reason it gave. On token grants it is a 403 with `error: invalid_grant`.\n- `signup_denied` (403): A pre-signup Action or an active block denied the sign-up. `message` carries the reason.\n- `client_credentials_denied` (401): An Action denied the client_credentials grant. `message` carries the reason.\n- `m2m_quota_exceeded` (402): The project used the machine-to-machine tokens its plan includes this month. Free is capped; Hobby and Pro are billed per token instead.\n- `signup_disabled` (403): Self-service sign-up is disabled on this connection.\n- `email_taken` (409): Another user in this account already uses that email.\n- `username_taken` (409): Another user of this database connection already uses that username.\n- `invalid_username` (400): The username is empty, or contains an `@` or whitespace. `message` says which.\n- `invalid_email` (400): The email address is not valid.\n- `invalid_name` (400): The name contains a link. `message` says which field.\n- `same_email` (400): The new email is the same as the current one.\n- `user_has_no_email` (400): The operation needs an email but the user has none.\n- `password_too_weak` (400): The password does not meet the connection policy. `message` lists each unmet rule.\n- `invalid_password_hash` (400): The imported password hash cannot be read, or its cost is above what a login can afford. `message` names the field.\n- `weak_password_hash` (400): The imported password hash uses a fast digest (MD5, SHA-1, SHA-2) or a cost below the minimum. `message` says which.\n- `invalid_code` (400): The verification code is wrong, expired or already used.\n- `invalid_phone` (400): The phone number is not E.164 and could not be resolved with the account default country. Include the country code.\n- `phone_changed` (400): The phone on the user changed after the code was sent. Start again.\n- `phone_already_verified` (409): The user already has a verified phone; the number cannot be swapped from the screen.\n- `sms_unavailable` (409): This account cannot send SMS right now. The suffix says why: `sms_unavailable:plan`, `:quota`, `:provider`.\n- `sms_failed` (409): The SMS provider rejected the message.\n- `invalid_state` (400): The `state` is missing, expired, or does not describe a resumable step.\n- `state_mismatch` (401): The `state` belongs to another account, session, client or ceremony.\n- `invalid_ticket` (400): The ticket does not exist or is not the kind this endpoint accepts.\n- `ticket_used` (400): The ticket was already consumed.\n- `ticket_expired` (400): The ticket is past its expiry.\n- `ticket_not_found` (404): No ticket with that id belongs to this user.\n- `credential_not_found` (404): The user has no password credential on this connection.\n- `invalid_link` (400): The magic link is malformed.\n- `expired_link` (400): The magic link token was not found or has expired.\n- `invalid_otp` (401): The one-time password is wrong or expired.\n- `invalid_client` (400): The `client_id` in the request does not name a client of this account.\n- `client_not_found` (404): No client with that `client_id`.\n- `client_mismatch` (401): The client belongs to a different account.\n- `invalid_client_metadata` (400): Dynamic client registration rejected a field (RFC 7591). `message` names it.\n- `invalid_connection` (400): The connection does not exist, is disabled, or is not of the type this flow needs.\n- `no_database_connection` (400): The tenant has no database connection, so there is nowhere to store a password. Create one and retry.\n- `connection_required` (400): No connection was given and the client has no `default_connection`.\n- `connection_misconfigured` (400): The connection is missing settings needed to talk to its provider.\n- `passwordless_unavailable` (400): No passwordless connection is configured or enabled for this client.\n- `ambiguous_connection` (400): Several connections match; pass `connection_id`.\n- `invalid_redirect_uri` (400): The redirect URI is not registered for the client.\n- `origin_not_allowed` (403): The request `Origin` is not in the client's Allowed Web Origins.\n- `audience_not_found` (403): The `audience` does not name an API registered in this account.\n- `system_resource` (403): The resource is managed by Faable and cannot be modified or deleted.\n- `invalid_request` (400): A required OAuth parameter is missing or two of them are incompatible. `message` says which.\n- `invalid_device_code` (400): The device or user code is invalid or expired.\n- `provider_error` (400): The upstream identity provider returned an error. The suffix is the provider’s own code, when it sent one: `provider_error:bad_refresh_token` (the user must re-authorize), `provider_error:incorrect_client_credentials` (our configuration, the user can do nothing). `details.provider_error_description` carries the provider’s sentence.\n- `identity_already_linked` (409): That external identity is already linked to another user.\n- `identity_link_denied` (409): That external identity cannot be linked to this user.\n- `identity_conflict` (409): The user already has a linked identity for this connection.\n- `identity_orphaned` (400): The identity pointed at a user that no longer exists; it was removed. Sign in again.\n- `no_provider_token` (400): The identity holds no provider access token.\n- `no_refresh_token` (400): The identity holds no provider refresh token, so it cannot be refreshed.\n- `action_unavailable` (401): The Action that paused this login is disabled or belongs elsewhere.\n- `login_flow_misconfigured` (500): The login flow of this account cannot run. `message` carries the node error.\n- `mfa_required` (403): The login needs a second factor that this flow cannot collect, or one is still pending on the session.\n- `step_up_required` (403): Confirm an existing factor before changing your factors.\n- `interaction_required` (403): An Action asked for a redirect on a non-interactive flow.\n- `passkey_login_disabled` (400): Sign in with a passkey is not enabled for this client.\n- `mfa_pending` (401): A second-factor challenge is pending; answer it before continuing.\n- `mfa_invalid_code` (401): The authenticator code did not verify.\n- `mfa_invalid_recovery_code` (401): The recovery code did not verify.\n- `too_many_attempts` (429): Too many wrong codes. Wait a few minutes and try again.\n- `too_many_login_attempts` (429): Too many failed sign-in attempts for this email or username from this network. Wait a few minutes and try again.\n- `totp_not_allowed` (401): This account does not accept authenticator apps.\n- `no_usable_factor` (400): The user has no confirmed second factor to challenge.\n- `factor_not_found` (400): No factor with that id belongs to this user.\n- `factor_already_confirmed` (400): The factor was already confirmed.\n- `invalid_factor` (400): The factor cannot be verified (no secret material).\n- `session_missing` (401): The session that started this login no longer exists.\n- `passkey_verification_failed` (400): The WebAuthn response could not be verified.\n- `no_passkey_enrolled` (400): The user has no passkey to sign in with.\n- `malformed_credential` (400): The WebAuthn credential is malformed.\n- `unknown_passkey` (401): The passkey is not enrolled for this user.\n- `invalid_passkey` (401): The passkey assertion did not verify.\n- `invalid_invite_url` (400): An invite's `accept_url` or `redirect_uri` is not an http(s) URL at an origin of this tenant's client callbacks or `callback_hostnames`, or it carries a fragment.\n- `invite_email_mismatch` (403): The invite is for another email address than the accepting user's. `details.invited_email` shows it masked.\n- `invite_email_unverified` (403): The accepting user's email matches the invite but is not verified yet.\n- `invite_not_found` (404): No invite with that id in this account.\n- `invite_used` (400): The invite was already accepted.\n- `already_member` (400): The user is already a member of the team.\n- `not_a_member` (404): The user is not a member of the team.\n- `registration_disabled` (403): Dynamic client registration is turned off for this tenant. Create the client from the dashboard or the Management API, or turn on `dynamic_client_registration_enabled`.\n- `invalid_email_domain` (400): Not an email domain this organization can claim: it must be a plain domain name (`acme.com`), lowercase, without scheme, path or wildcard.\n- `public_email_domain` (400): A public email provider (gmail.com, outlook.com…) cannot belong to an organization: anyone can have an address there.\n- `organization_domain_not_found` (404): The organization has no such domain.\n- `organization_domain_taken` (409): Another organization of this tenant already verified this domain. A domain belongs to one organization.\n- `organization_domain_unverified` (400): The TXT record was not found or does not hold the expected value yet. `details.record` says what was expected and what resolves now; DNS can take a few minutes to propagate.\n- `plan_unavailable` (503): The plan could not be checked right now, and this setting is only for paid plans. Try again in a minute.\n- `organization_domain_mismatch` (403): This organization's identity provider can only sign in addresses of the organization's verified email domains.\n- `team_not_in_organization` (400): Auto-join can only put people in teams of the same organization. `details.teams` lists the others.\n- `organization_has_no_idp` (400): Requiring SSO needs an identity provider: bind an `oidc` connection to the organization first.\n- `organization_not_found` (404): No organization with that id in this account.\n- `invalid_user` (400): The user does not exist in this account.\n- `not_an_organization_admin` (404): The user is not an admin of the organization.\n- `last_organization_admin` (409): An organization keeps at least one admin. Add another admin before removing this one.\n- `team_id_unavailable` (409): The team id cannot be used in this tenant. Pick another id or let the API generate one.\n- `use_team_member_route` (400): This generic route cannot create memberships. Use `POST /team/{team_id}/member` for team members or `POST /role/{role_id}/users` for role grants.\n- `role_not_found` (404): No role with that id in this account.\n- `invalid_role` (400): The role belongs to another account.\n- `flow_not_found` (400): The login flow does not exist in this account.\n- `revision_not_found` (404): The revision is not in the flow history.\n- `invalid_webhook_event` (400): An event is not in the webhook event catalog. `message` and `details.valid_events` list the valid ones.\n- `invalid_webhook_url` (400): The webhook URL must be an absolute `https` URL.\n- `not_a_webhook` (400): The operation only applies to `webhook` subscriptions.\n- `delivery_not_found` (404): No webhook delivery with that id for this subscription.\n- `delivery_in_progress` (409): The delivery is being attempted right now; retry the redeliver in a minute.",
8024
+ "description": "Machine-readable error code. One HTTP status per code.\n\n- `bad_request` (400): The request is malformed. `message` says what is wrong.\n- `validation_error` (400): The body, query or path failed schema validation. `details.issues` lists each failing field.\n- `unauthorized` (401): The request carries no valid credentials.\n- `payment_required` (402): The feature is not included in the current plan.\n- `forbidden` (403): The credentials are valid but do not allow this operation.\n- `not_found` (404): The resource does not exist in this account.\n- `method_not_allowed` (405): The HTTP method is not supported on this path.\n- `conflict` (409): The request conflicts with the current state of the resource.\n- `payload_too_large` (413): The request body exceeds the size limit.\n- `unsupported_media_type` (415): The `Content-Type` is not accepted by this endpoint.\n- `unprocessable_entity` (422): The request is well-formed but cannot be processed.\n- `too_many_requests` (429): Rate limit exceeded. Honour the `Retry-After` header.\n- `internal_error` (500): Unexpected server error. Retry later; the request id is logged.\n- `already_exists` (400): A resource with the same unique field already exists (for a user, usually `email`). `details.fields` names the field.\n- `invalid_id` (400): The id in the path is not a valid id for this resource.\n- `account_not_found` (404): No Auth Account matches the request (domain, header or token).\n- `invalid_query` (400): The `?query=` FaableQL expression could not be parsed.\n- `search_not_supported` (400): This resource does not support `?search=`.\n- `invalid_expand` (400): An `?expand=` path is not allowed on this resource.\n- `access_denied` (401): The caller may not access this row (ownership or machine-to-machine restriction).\n- `insufficient_scope` (403): The token lacks a scope this operation requires. `message` names it.\n- `team_required` (400): An Auth Account must belong to a project (team).\n- `account_limit_reached` (409): The project already has the maximum number of Auth Accounts.\n- `invalid_project_id` (400): The project id is not of the form `project_<hex>` or `team_<hex>`.\n- `account_transfer_refused` (409): The Auth Account cannot be moved to that project. `details.blockers` lists why.\n- `email_sender_domain_not_allowed` (400): The sender address is not in a domain this platform signs email for (AUTH_EMAIL_SENDER_DOMAINS).\n- `plan_required` (402): The setting requires a higher plan. `message` says which.\n- `invalid_canonical_host` (400): `canonical_host` must be this account's own platform host or one of its verified custom domains.\n- `canonical_host_breaks_passkeys` (400): `canonical_host` is outside the account's current WebAuthn RP ID — every passkey already enrolled would stop working. Set `webauthn_rp_id` in the same request to a suffix that covers both.\n- `not_logged_in` (401): There is no signed-in session for this request.\n- `session_already_revoked` (409): The session was already revoked.\n- `invalid_token` (401): The bearer token is missing, malformed, expired or has no subject.\n- `not_owner` (403): The caller may only perform this operation on their own user.\n- `user_suspended` (403): The user is suspended and cannot sign in or be modified.\n- `invalid_credentials` (400): The email/username or password is incorrect.\n- `login_denied` (401): A post-login Action denied the sign-in. `message` carries the reason it gave. On token grants it is a 403 with `error: invalid_grant`.\n- `signup_denied` (403): A pre-signup Action or an active block denied the sign-up. `message` carries the reason.\n- `client_credentials_denied` (401): An Action denied the client_credentials grant. `message` carries the reason.\n- `m2m_quota_exceeded` (402): The project used the machine-to-machine tokens its plan includes this month. Free is capped; Hobby and Pro are billed per token instead.\n- `signup_disabled` (403): Self-service sign-up is disabled on this connection.\n- `email_taken` (409): Another user in this account already uses that email.\n- `username_taken` (409): Another user of this database connection already uses that username.\n- `invalid_username` (400): The username is empty, or contains an `@` or whitespace. `message` says which.\n- `invalid_email` (400): The email address is not valid.\n- `invalid_name` (400): The name contains a link. `message` says which field.\n- `same_email` (400): The new email is the same as the current one.\n- `user_has_no_email` (400): The operation needs an email but the user has none.\n- `password_too_weak` (400): The password does not meet the connection policy. `message` lists each unmet rule.\n- `invalid_password_hash` (400): The imported password hash cannot be read, or its cost is above what a login can afford. `message` names the field.\n- `weak_password_hash` (400): The imported password hash uses a fast digest (MD5, SHA-1, SHA-2) or a cost below the minimum. `message` says which.\n- `invalid_code` (400): The verification code is wrong, expired or already used.\n- `invalid_phone` (400): The phone number is not E.164 and could not be resolved with the account default country. Include the country code.\n- `phone_changed` (400): The phone on the user changed after the code was sent. Start again.\n- `phone_already_verified` (409): The user already has a verified phone; the number cannot be swapped from the screen.\n- `sms_unavailable` (409): This account cannot send SMS right now. The suffix says why: `sms_unavailable:plan`, `:quota`, `:provider`.\n- `sms_failed` (409): The SMS provider rejected the message.\n- `invalid_state` (400): The `state` is missing, expired, or does not describe a resumable step.\n- `state_mismatch` (401): The `state` belongs to another account, session, client or ceremony.\n- `invalid_ticket` (400): The ticket does not exist or is not the kind this endpoint accepts.\n- `ticket_used` (400): The ticket was already consumed.\n- `ticket_expired` (400): The ticket is past its expiry.\n- `ticket_not_found` (404): No ticket with that id belongs to this user.\n- `credential_not_found` (404): The user has no password credential on this connection.\n- `invalid_link` (400): The magic link is malformed.\n- `expired_link` (400): The magic link token was not found or has expired.\n- `invalid_otp` (401): The one-time password is wrong or expired.\n- `invalid_client` (400): The `client_id` in the request does not name a client of this account.\n- `client_not_found` (404): No client with that `client_id`.\n- `client_mismatch` (401): The client belongs to a different account.\n- `invalid_client_metadata` (400): Dynamic client registration rejected a field (RFC 7591). `message` names it.\n- `invalid_connection` (400): The connection does not exist, is disabled, or is not of the type this flow needs.\n- `no_database_connection` (400): The tenant has no database connection, so there is nowhere to store a password. Create one and retry.\n- `connection_required` (400): No connection was given and the client has no `default_connection`.\n- `connection_misconfigured` (400): The connection is missing settings needed to talk to its provider.\n- `passwordless_unavailable` (400): No passwordless connection is configured or enabled for this client.\n- `ambiguous_connection` (400): Several connections match; pass `connection_id`.\n- `invalid_redirect_uri` (400): The redirect URI is not registered for the client.\n- `origin_not_allowed` (403): The request `Origin` is not in the client's Allowed Web Origins.\n- `audience_not_found` (403): The `audience` does not name an API registered in this account.\n- `system_resource` (403): The resource is managed by Faable and cannot be modified or deleted.\n- `invalid_request` (400): A required OAuth parameter is missing or two of them are incompatible. `message` says which.\n- `invalid_device_code` (400): The device or user code is invalid or expired.\n- `provider_error` (400): The upstream identity provider returned an error. The suffix is the provider’s own code, when it sent one: `provider_error:bad_refresh_token` (the user must re-authorize), `provider_error:incorrect_client_credentials` (our configuration, the user can do nothing). `details.provider_error_description` carries the provider’s sentence.\n- `identity_already_linked` (409): That external identity is already linked to another user.\n- `identity_link_denied` (409): That external identity cannot be linked to this user.\n- `identity_conflict` (409): The user already has a linked identity for this connection.\n- `identity_orphaned` (400): The identity pointed at a user that no longer exists; it was removed. Sign in again.\n- `no_provider_token` (400): The identity holds no provider access token.\n- `no_refresh_token` (400): The identity holds no provider refresh token, so it cannot be refreshed.\n- `action_unavailable` (401): The Action that paused this login is disabled or belongs elsewhere.\n- `login_flow_misconfigured` (500): The login flow of this account cannot run. `message` carries the node error.\n- `mfa_required` (403): The login needs a second factor that this flow cannot collect, or one is still pending on the session.\n- `step_up_required` (403): Confirm an existing factor before changing your factors.\n- `interaction_required` (403): An Action asked for a redirect on a non-interactive flow.\n- `passkey_login_disabled` (400): Sign in with a passkey is not enabled for this client.\n- `mfa_pending` (401): A second-factor challenge is pending; answer it before continuing.\n- `mfa_invalid_code` (401): The authenticator code did not verify.\n- `mfa_invalid_recovery_code` (401): The recovery code did not verify.\n- `too_many_attempts` (429): Too many wrong codes. Wait a few minutes and try again.\n- `too_many_login_attempts` (429): Too many failed sign-in attempts for this email or username from this network. Wait a few minutes and try again.\n- `totp_not_allowed` (401): This account does not accept authenticator apps.\n- `no_usable_factor` (400): The user has no confirmed second factor to challenge.\n- `factor_not_found` (400): No factor with that id belongs to this user.\n- `factor_already_confirmed` (400): The factor was already confirmed.\n- `invalid_factor` (400): The factor cannot be verified (no secret material).\n- `session_missing` (401): The session that started this login no longer exists.\n- `passkey_verification_failed` (400): The WebAuthn response could not be verified.\n- `no_passkey_enrolled` (400): The user has no passkey to sign in with.\n- `malformed_credential` (400): The WebAuthn credential is malformed.\n- `unknown_passkey` (401): The passkey is not enrolled for this user.\n- `invalid_passkey` (401): The passkey assertion did not verify.\n- `invalid_invite_url` (400): An invite's `accept_url` or `redirect_uri` is not an http(s) URL at an origin of this tenant's client callbacks or `callback_hostnames`, or it carries a fragment.\n- `invite_email_mismatch` (403): The invite is for another email address than the accepting user's. `details.invited_email` shows it masked.\n- `invite_email_unverified` (403): The accepting user's email matches the invite but is not verified yet.\n- `invite_not_found` (404): No invite with that id in this account.\n- `invite_used` (400): The invite was already accepted.\n- `already_member` (400): The user is already a member of the team.\n- `not_a_member` (404): The user is not a member of the team.\n- `consent_options_unavailable` (502): The consent screen could not load the choices from the API being authorized (its `consent_options.url`). Try again in a moment.\n- `consent_choice_invalid` (400): The choice sent with the consent decision is not one the API offered for this user.\n- `registration_disabled` (403): Dynamic client registration is turned off for this tenant. Create the client from the dashboard or the Management API, or turn on `dynamic_client_registration_enabled`.\n- `invalid_email_domain` (400): Not an email domain this organization can claim: it must be a plain domain name (`acme.com`), lowercase, without scheme, path or wildcard.\n- `public_email_domain` (400): A public email provider (gmail.com, outlook.com…) cannot belong to an organization: anyone can have an address there.\n- `organization_domain_not_found` (404): The organization has no such domain.\n- `organization_domain_taken` (409): Another organization of this tenant already verified this domain. A domain belongs to one organization.\n- `organization_domain_unverified` (400): The TXT record was not found or does not hold the expected value yet. `details.record` says what was expected and what resolves now; DNS can take a few minutes to propagate.\n- `plan_unavailable` (503): The plan could not be checked right now, and this setting is only for paid plans. Try again in a minute.\n- `organization_domain_mismatch` (403): This organization's identity provider can only sign in addresses of the organization's verified email domains.\n- `team_not_in_organization` (400): Auto-join can only put people in teams of the same organization. `details.teams` lists the others.\n- `organization_has_no_idp` (400): Requiring SSO needs an identity provider: bind an `oidc` connection to the organization first.\n- `organization_not_found` (404): No organization with that id in this account.\n- `invalid_user` (400): The user does not exist in this account.\n- `not_an_organization_admin` (404): The user is not an admin of the organization.\n- `last_organization_admin` (409): An organization keeps at least one admin. Add another admin before removing this one.\n- `team_id_unavailable` (409): The team id cannot be used in this tenant. Pick another id or let the API generate one.\n- `use_team_member_route` (400): This generic route cannot create memberships. Use `POST /team/{team_id}/member` for team members or `POST /role/{role_id}/users` for role grants.\n- `role_not_found` (404): No role with that id in this account.\n- `invalid_role` (400): The role belongs to another account.\n- `flow_not_found` (400): The login flow does not exist in this account.\n- `revision_not_found` (404): The revision is not in the flow history.\n- `invalid_webhook_event` (400): An event is not in the webhook event catalog. `message` and `details.valid_events` list the valid ones.\n- `invalid_webhook_url` (400): The webhook URL must be an absolute `https` URL.\n- `not_a_webhook` (400): The operation only applies to `webhook` subscriptions.\n- `delivery_not_found` (404): No webhook delivery with that id for this subscription.\n- `delivery_in_progress` (409): The delivery is being attempted right now; retry the redeliver in a minute.",
7862
8025
  "enum": [
7863
8026
  "bad_request",
7864
8027
  "validation_error",
@@ -7978,6 +8141,8 @@
7978
8141
  "invite_used",
7979
8142
  "already_member",
7980
8143
  "not_a_member",
8144
+ "consent_options_unavailable",
8145
+ "consent_choice_invalid",
7981
8146
  "registration_disabled",
7982
8147
  "invalid_email_domain",
7983
8148
  "public_email_domain",
@@ -8659,6 +8824,10 @@
8659
8824
  "type": "boolean",
8660
8825
  "description": "When true, anyone can register a client with `POST /oidc/register` (OIDC Dynamic Client Registration / RFC 7591) and the discovery document advertises `registration_endpoint`. Off by default: an open registration lets anyone create a client with their own `redirect_uri`."
8661
8826
  },
8827
+ "client_id_metadata_documents_enabled": {
8828
+ "type": "boolean",
8829
+ "description": "When true, /authorize accepts a `client_id` that is an https URL serving a Client ID Metadata Document (the MCP authorization way to identify a client without registering it). Such clients always see the consent screen. Off by default."
8830
+ },
8662
8831
  "canonical_host": {
8663
8832
  "type": "string",
8664
8833
  "description": "The one host this tenant's OIDC issuer and discovery document are always minted with, regardless of which host actually served the request — must be the account's own platform host or one of its verified custom domains. `/authorize` and `/logout` 302 here from any other host of the tenant. Unset (the default): every URL uses whatever host served the request, as before this field existed. Changing it can invalidate every WebAuthn passkey already enrolled unless `webauthn_rp_id` already covers the new host.",
@@ -9407,6 +9576,10 @@
9407
9576
  "type": "boolean",
9408
9577
  "description": "When true, anyone can register a client with `POST /oidc/register` (OIDC Dynamic Client Registration / RFC 7591) and the discovery document advertises `registration_endpoint`. Off by default: an open registration lets anyone create a client with their own `redirect_uri`."
9409
9578
  },
9579
+ "client_id_metadata_documents_enabled": {
9580
+ "type": "boolean",
9581
+ "description": "When true, /authorize accepts a `client_id` that is an https URL serving a Client ID Metadata Document (the MCP authorization way to identify a client without registering it). Such clients always see the consent screen. Off by default."
9582
+ },
9410
9583
  "canonical_host": {
9411
9584
  "type": "string",
9412
9585
  "description": "The one host this tenant's OIDC issuer and discovery document are always minted with, regardless of which host actually served the request — must be the account's own platform host or one of its verified custom domains. `/authorize` and `/logout` 302 here from any other host of the tenant. Unset (the default): every URL uses whatever host served the request, as before this field existed. Changing it can invalidate every WebAuthn passkey already enrolled unless `webauthn_rp_id` already covers the new host.",
@@ -10392,6 +10565,10 @@
10392
10565
  "type": "boolean",
10393
10566
  "description": "When true, anyone can register a client with `POST /oidc/register` (OIDC Dynamic Client Registration / RFC 7591) and the discovery document advertises `registration_endpoint`. Off by default: an open registration lets anyone create a client with their own `redirect_uri`."
10394
10567
  },
10568
+ "client_id_metadata_documents_enabled": {
10569
+ "type": "boolean",
10570
+ "description": "When true, /authorize accepts a `client_id` that is an https URL serving a Client ID Metadata Document (the MCP authorization way to identify a client without registering it). Such clients always see the consent screen. Off by default."
10571
+ },
10395
10572
  "canonical_host": {
10396
10573
  "type": "string",
10397
10574
  "description": "The one host this tenant's OIDC issuer and discovery document are always minted with, regardless of which host actually served the request — must be the account's own platform host or one of its verified custom domains. `/authorize` and `/logout` 302 here from any other host of the tenant. Unset (the default): every URL uses whatever host served the request, as before this field existed. Changing it can invalidate every WebAuthn passkey already enrolled unless `webauthn_rp_id` already covers the new host.",
@@ -11021,6 +11198,10 @@
11021
11198
  "type": "boolean",
11022
11199
  "nullable": true
11023
11200
  },
11201
+ "client_id_metadata_documents_enabled": {
11202
+ "type": "boolean",
11203
+ "nullable": true
11204
+ },
11024
11205
  "canonical_host": {
11025
11206
  "type": "string",
11026
11207
  "nullable": true
@@ -11557,6 +11738,10 @@
11557
11738
  "type": "boolean",
11558
11739
  "description": "When true, anyone can register a client with `POST /oidc/register` (OIDC Dynamic Client Registration / RFC 7591) and the discovery document advertises `registration_endpoint`. Off by default: an open registration lets anyone create a client with their own `redirect_uri`."
11559
11740
  },
11741
+ "client_id_metadata_documents_enabled": {
11742
+ "type": "boolean",
11743
+ "description": "When true, /authorize accepts a `client_id` that is an https URL serving a Client ID Metadata Document (the MCP authorization way to identify a client without registering it). Such clients always see the consent screen. Off by default."
11744
+ },
11560
11745
  "canonical_host": {
11561
11746
  "type": "string",
11562
11747
  "description": "The one host this tenant's OIDC issuer and discovery document are always minted with, regardless of which host actually served the request — must be the account's own platform host or one of its verified custom domains. `/authorize` and `/logout` 302 here from any other host of the tenant. Unset (the default): every URL uses whatever host served the request, as before this field existed. Changing it can invalidate every WebAuthn passkey already enrolled unless `webauthn_rp_id` already covers the new host.",
@@ -12138,6 +12323,21 @@
12138
12323
  "maximum": 900,
12139
12324
  "default": 900,
12140
12325
  "description": "Lifetime in seconds."
12326
+ },
12327
+ "scopes": {
12328
+ "type": "array",
12329
+ "items": {
12330
+ "type": "string"
12331
+ },
12332
+ "minItems": 1,
12333
+ "uniqueItems": true,
12334
+ "description": "Narrow the token to these management scopes (each must be in the catalog). Omitted: the whole catalog."
12335
+ },
12336
+ "apikey_id": {
12337
+ "type": "string",
12338
+ "minLength": 1,
12339
+ "maxLength": 64,
12340
+ "description": "Set when the user acts through one of their deploy API keys (the hosted MCP). Recorded in the audit log and as `via_apikey` in the token."
12141
12341
  }
12142
12342
  },
12143
12343
  "additionalProperties": false
@@ -14503,6 +14703,10 @@
14503
14703
  "type": "boolean",
14504
14704
  "description": "When true, anyone can register a client with `POST /oidc/register` (OIDC Dynamic Client Registration / RFC 7591) and the discovery document advertises `registration_endpoint`. Off by default: an open registration lets anyone create a client with their own `redirect_uri`."
14505
14705
  },
14706
+ "client_id_metadata_documents_enabled": {
14707
+ "type": "boolean",
14708
+ "description": "When true, /authorize accepts a `client_id` that is an https URL serving a Client ID Metadata Document (the MCP authorization way to identify a client without registering it). Such clients always see the consent screen. Off by default."
14709
+ },
14506
14710
  "canonical_host": {
14507
14711
  "type": "string",
14508
14712
  "description": "The one host this tenant's OIDC issuer and discovery document are always minted with, regardless of which host actually served the request — must be the account's own platform host or one of its verified custom domains. `/authorize` and `/logout` 302 here from any other host of the tenant. Unset (the default): every URL uses whatever host served the request, as before this field existed. Changing it can invalidate every WebAuthn passkey already enrolled unless `webauthn_rp_id` already covers the new host.",
@@ -14743,6 +14947,15 @@
14743
14947
  "required": false,
14744
14948
  "description": "Exact match on `category`. Equivalent to `?query=category:<value>`."
14745
14949
  },
14950
+ {
14951
+ "schema": {
14952
+ "type": "boolean"
14953
+ },
14954
+ "in": "query",
14955
+ "name": "count",
14956
+ "required": false,
14957
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
14958
+ },
14746
14959
  {
14747
14960
  "schema": {
14748
14961
  "type": "string"
@@ -14796,6 +15009,10 @@
14796
15009
  "items": {
14797
15010
  "$ref": "#/components/schemas/Connection"
14798
15011
  }
15012
+ },
15013
+ "total": {
15014
+ "type": "integer",
15015
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
14799
15016
  }
14800
15017
  },
14801
15018
  "additionalProperties": false
@@ -17866,6 +18083,15 @@
17866
18083
  "required": false,
17867
18084
  "description": "Cursor returned by the previous page"
17868
18085
  },
18086
+ {
18087
+ "schema": {
18088
+ "type": "boolean"
18089
+ },
18090
+ "in": "query",
18091
+ "name": "count",
18092
+ "required": false,
18093
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
18094
+ },
17869
18095
  {
17870
18096
  "schema": {
17871
18097
  "type": "string"
@@ -17919,6 +18145,10 @@
17919
18145
  "items": {
17920
18146
  "$ref": "#/components/schemas/Client"
17921
18147
  }
18148
+ },
18149
+ "total": {
18150
+ "type": "integer",
18151
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
17922
18152
  }
17923
18153
  },
17924
18154
  "additionalProperties": false
@@ -18331,6 +18561,17 @@
18331
18561
  "token_endpoint_auth_method": {
18332
18562
  "type": "string"
18333
18563
  },
18564
+ "consent_required": {
18565
+ "type": "boolean",
18566
+ "description": "When true, /authorize never issues a code in silence for this client: the End-User approves it on the consent screen first. Set on clients the tenant did not create (Client ID Metadata Documents, dynamic registration)."
18567
+ },
18568
+ "metadata_document_url": {
18569
+ "type": "string",
18570
+ "description": "For a client identified by a Client ID Metadata Document: the URL (also its client_id) its metadata was fetched from."
18571
+ },
18572
+ "registered_dynamically": {
18573
+ "type": "boolean"
18574
+ },
18334
18575
  "application_type": {
18335
18576
  "type": "string"
18336
18577
  },
@@ -18973,6 +19214,17 @@
18973
19214
  "token_endpoint_auth_method": {
18974
19215
  "type": "string"
18975
19216
  },
19217
+ "consent_required": {
19218
+ "type": "boolean",
19219
+ "description": "When true, /authorize never issues a code in silence for this client: the End-User approves it on the consent screen first. Set on clients the tenant did not create (Client ID Metadata Documents, dynamic registration)."
19220
+ },
19221
+ "metadata_document_url": {
19222
+ "type": "string",
19223
+ "description": "For a client identified by a Client ID Metadata Document: the URL (also its client_id) its metadata was fetched from."
19224
+ },
19225
+ "registered_dynamically": {
19226
+ "type": "boolean"
19227
+ },
18976
19228
  "application_type": {
18977
19229
  "type": "string"
18978
19230
  },
@@ -20126,6 +20378,17 @@
20126
20378
  "token_endpoint_auth_method": {
20127
20379
  "type": "string"
20128
20380
  },
20381
+ "consent_required": {
20382
+ "type": "boolean",
20383
+ "description": "When true, /authorize never issues a code in silence for this client: the End-User approves it on the consent screen first. Set on clients the tenant did not create (Client ID Metadata Documents, dynamic registration)."
20384
+ },
20385
+ "metadata_document_url": {
20386
+ "type": "string",
20387
+ "description": "For a client identified by a Client ID Metadata Document: the URL (also its client_id) its metadata was fetched from."
20388
+ },
20389
+ "registered_dynamically": {
20390
+ "type": "boolean"
20391
+ },
20129
20392
  "application_type": {
20130
20393
  "type": "string"
20131
20394
  },
@@ -20768,6 +21031,17 @@
20768
21031
  "token_endpoint_auth_method": {
20769
21032
  "type": "string"
20770
21033
  },
21034
+ "consent_required": {
21035
+ "type": "boolean",
21036
+ "description": "When true, /authorize never issues a code in silence for this client: the End-User approves it on the consent screen first. Set on clients the tenant did not create (Client ID Metadata Documents, dynamic registration)."
21037
+ },
21038
+ "metadata_document_url": {
21039
+ "type": "string",
21040
+ "description": "For a client identified by a Client ID Metadata Document: the URL (also its client_id) its metadata was fetched from."
21041
+ },
21042
+ "registered_dynamically": {
21043
+ "type": "boolean"
21044
+ },
20771
21045
  "application_type": {
20772
21046
  "type": "string"
20773
21047
  },
@@ -21411,6 +21685,17 @@
21411
21685
  "token_endpoint_auth_method": {
21412
21686
  "type": "string"
21413
21687
  },
21688
+ "consent_required": {
21689
+ "type": "boolean",
21690
+ "description": "When true, /authorize never issues a code in silence for this client: the End-User approves it on the consent screen first. Set on clients the tenant did not create (Client ID Metadata Documents, dynamic registration)."
21691
+ },
21692
+ "metadata_document_url": {
21693
+ "type": "string",
21694
+ "description": "For a client identified by a Client ID Metadata Document: the URL (also its client_id) its metadata was fetched from."
21695
+ },
21696
+ "registered_dynamically": {
21697
+ "type": "boolean"
21698
+ },
21414
21699
  "application_type": {
21415
21700
  "type": "string"
21416
21701
  },
@@ -22016,6 +22301,60 @@
22016
22301
  "required": false,
22017
22302
  "description": "Exact match on `suspended`. Equivalent to `?query=suspended:<value>`."
22018
22303
  },
22304
+ {
22305
+ "schema": {
22306
+ "type": "string"
22307
+ },
22308
+ "in": "query",
22309
+ "name": "last_login_since",
22310
+ "required": false,
22311
+ "description": "Exact match on `last_login_since`. Equivalent to `?query=last_login_since:<value>`."
22312
+ },
22313
+ {
22314
+ "schema": {
22315
+ "type": "string"
22316
+ },
22317
+ "in": "query",
22318
+ "name": "last_login_until",
22319
+ "required": false,
22320
+ "description": "Exact match on `last_login_until`. Equivalent to `?query=last_login_until:<value>`."
22321
+ },
22322
+ {
22323
+ "schema": {
22324
+ "type": "string"
22325
+ },
22326
+ "in": "query",
22327
+ "name": "created_since",
22328
+ "required": false,
22329
+ "description": "Exact match on `created_since`. Equivalent to `?query=created_since:<value>`."
22330
+ },
22331
+ {
22332
+ "schema": {
22333
+ "type": "string"
22334
+ },
22335
+ "in": "query",
22336
+ "name": "created_until",
22337
+ "required": false,
22338
+ "description": "Exact match on `created_until`. Equivalent to `?query=created_until:<value>`."
22339
+ },
22340
+ {
22341
+ "schema": {
22342
+ "type": "string"
22343
+ },
22344
+ "in": "query",
22345
+ "name": "sort",
22346
+ "required": false,
22347
+ "description": "Sort by one field: `<field>` ascending, `-<field>` descending. One of: createdAt, last_login, logins_count. Rows with no value in that field are left out. Default: `-createdAt`."
22348
+ },
22349
+ {
22350
+ "schema": {
22351
+ "type": "boolean"
22352
+ },
22353
+ "in": "query",
22354
+ "name": "count",
22355
+ "required": false,
22356
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
22357
+ },
22019
22358
  {
22020
22359
  "schema": {
22021
22360
  "type": "string"
@@ -22069,6 +22408,10 @@
22069
22408
  "items": {
22070
22409
  "$ref": "#/components/schemas/User"
22071
22410
  }
22411
+ },
22412
+ "total": {
22413
+ "type": "integer",
22414
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
22072
22415
  }
22073
22416
  },
22074
22417
  "additionalProperties": false
@@ -28396,6 +28739,15 @@
28396
28739
  "required": false,
28397
28740
  "description": "Exact match on `created_at`. Equivalent to `?query=created_at:<value>`."
28398
28741
  },
28742
+ {
28743
+ "schema": {
28744
+ "type": "boolean"
28745
+ },
28746
+ "in": "query",
28747
+ "name": "count",
28748
+ "required": false,
28749
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
28750
+ },
28399
28751
  {
28400
28752
  "schema": {
28401
28753
  "type": "string"
@@ -28456,6 +28808,10 @@
28456
28808
  "items": {
28457
28809
  "$ref": "#/components/schemas/Identity"
28458
28810
  }
28811
+ },
28812
+ "total": {
28813
+ "type": "integer",
28814
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
28459
28815
  }
28460
28816
  },
28461
28817
  "additionalProperties": false
@@ -29757,6 +30113,15 @@
29757
30113
  "required": false,
29758
30114
  "description": "Exact match on `created_at`. Equivalent to `?query=created_at:<value>`."
29759
30115
  },
30116
+ {
30117
+ "schema": {
30118
+ "type": "boolean"
30119
+ },
30120
+ "in": "query",
30121
+ "name": "count",
30122
+ "required": false,
30123
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
30124
+ },
29760
30125
  {
29761
30126
  "schema": {
29762
30127
  "type": "string"
@@ -29828,6 +30193,10 @@
29828
30193
  "items": {
29829
30194
  "$ref": "#/components/schemas/Credential"
29830
30195
  }
30196
+ },
30197
+ "total": {
30198
+ "type": "integer",
30199
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
29831
30200
  }
29832
30201
  },
29833
30202
  "additionalProperties": false
@@ -31421,6 +31790,15 @@
31421
31790
  "required": false,
31422
31791
  "description": "Cursor returned by the previous page"
31423
31792
  },
31793
+ {
31794
+ "schema": {
31795
+ "type": "boolean"
31796
+ },
31797
+ "in": "query",
31798
+ "name": "count",
31799
+ "required": false,
31800
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
31801
+ },
31424
31802
  {
31425
31803
  "schema": {
31426
31804
  "type": "string"
@@ -31474,6 +31852,10 @@
31474
31852
  "items": {
31475
31853
  "$ref": "#/components/schemas/Role"
31476
31854
  }
31855
+ },
31856
+ "total": {
31857
+ "type": "integer",
31858
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
31477
31859
  }
31478
31860
  },
31479
31861
  "additionalProperties": false
@@ -33097,6 +33479,15 @@
33097
33479
  "required": false,
33098
33480
  "description": "Cursor returned by the previous page"
33099
33481
  },
33482
+ {
33483
+ "schema": {
33484
+ "type": "boolean"
33485
+ },
33486
+ "in": "query",
33487
+ "name": "count",
33488
+ "required": false,
33489
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
33490
+ },
33100
33491
  {
33101
33492
  "schema": {
33102
33493
  "type": "string"
@@ -33157,6 +33548,10 @@
33157
33548
  "items": {
33158
33549
  "$ref": "#/components/schemas/RoleMember"
33159
33550
  }
33551
+ },
33552
+ "total": {
33553
+ "type": "integer",
33554
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
33160
33555
  }
33161
33556
  },
33162
33557
  "additionalProperties": false
@@ -33873,6 +34268,15 @@
33873
34268
  "required": false,
33874
34269
  "description": "Cursor returned by the previous page"
33875
34270
  },
34271
+ {
34272
+ "schema": {
34273
+ "type": "boolean"
34274
+ },
34275
+ "in": "query",
34276
+ "name": "count",
34277
+ "required": false,
34278
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
34279
+ },
33876
34280
  {
33877
34281
  "schema": {
33878
34282
  "type": "string"
@@ -33926,6 +34330,10 @@
33926
34330
  "items": {
33927
34331
  "$ref": "#/components/schemas/Team"
33928
34332
  }
34333
+ },
34334
+ "total": {
34335
+ "type": "integer",
34336
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
33929
34337
  }
33930
34338
  },
33931
34339
  "additionalProperties": false
@@ -35838,6 +36246,15 @@
35838
36246
  "required": false,
35839
36247
  "description": "Cursor returned by the previous page"
35840
36248
  },
36249
+ {
36250
+ "schema": {
36251
+ "type": "boolean"
36252
+ },
36253
+ "in": "query",
36254
+ "name": "count",
36255
+ "required": false,
36256
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
36257
+ },
35841
36258
  {
35842
36259
  "schema": {
35843
36260
  "type": "string"
@@ -35891,6 +36308,10 @@
35891
36308
  "items": {
35892
36309
  "$ref": "#/components/schemas/Organization"
35893
36310
  }
36311
+ },
36312
+ "total": {
36313
+ "type": "integer",
36314
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
35894
36315
  }
35895
36316
  },
35896
36317
  "additionalProperties": false
@@ -40005,6 +40426,15 @@
40005
40426
  "required": false,
40006
40427
  "description": "Exact match on `team`. Equivalent to `?query=team:<value>`."
40007
40428
  },
40429
+ {
40430
+ "schema": {
40431
+ "type": "boolean"
40432
+ },
40433
+ "in": "query",
40434
+ "name": "count",
40435
+ "required": false,
40436
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
40437
+ },
40008
40438
  {
40009
40439
  "schema": {
40010
40440
  "type": "string"
@@ -40066,6 +40496,10 @@
40066
40496
  "items": {
40067
40497
  "$ref": "#/components/schemas/TeamMember"
40068
40498
  }
40499
+ },
40500
+ "total": {
40501
+ "type": "integer",
40502
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
40069
40503
  }
40070
40504
  },
40071
40505
  "additionalProperties": false
@@ -44007,6 +44441,15 @@
44007
44441
  "required": false,
44008
44442
  "description": "Exact match on `allow_offline_access`. Equivalent to `?query=allow_offline_access:<value>`."
44009
44443
  },
44444
+ {
44445
+ "schema": {
44446
+ "type": "boolean"
44447
+ },
44448
+ "in": "query",
44449
+ "name": "count",
44450
+ "required": false,
44451
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
44452
+ },
44010
44453
  {
44011
44454
  "schema": {
44012
44455
  "type": "string"
@@ -44060,6 +44503,10 @@
44060
44503
  "items": {
44061
44504
  "$ref": "#/components/schemas/Api"
44062
44505
  }
44506
+ },
44507
+ "total": {
44508
+ "type": "integer",
44509
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
44063
44510
  }
44064
44511
  },
44065
44512
  "additionalProperties": false
@@ -44306,6 +44753,53 @@
44306
44753
  "type": "boolean",
44307
44754
  "description": "When true, clients can request `offline_access` and receive a refresh_token for this API."
44308
44755
  },
44756
+ "consent_options": {
44757
+ "type": "object",
44758
+ "required": [
44759
+ "claim",
44760
+ "label",
44761
+ "url",
44762
+ "audience"
44763
+ ],
44764
+ "properties": {
44765
+ "claim": {
44766
+ "type": "string",
44767
+ "pattern": "^[a-z][a-z0-9_]{0,31}$",
44768
+ "description": "Access token claim that carries the chosen id."
44769
+ },
44770
+ "label": {
44771
+ "type": "string",
44772
+ "maxLength": 60,
44773
+ "description": "What the screen asks for, e.g. \"Project\"."
44774
+ },
44775
+ "url": {
44776
+ "type": "string",
44777
+ "pattern": "^https://",
44778
+ "description": "GET endpoint of the resource server that lists the choices."
44779
+ },
44780
+ "audience": {
44781
+ "type": "string",
44782
+ "description": "Identifier of a registered API the listing token is issued for (usually the resource server behind `url`)."
44783
+ }
44784
+ }
44785
+ },
44786
+ "delegation": {
44787
+ "type": "object",
44788
+ "required": [
44789
+ "client_id",
44790
+ "audience"
44791
+ ],
44792
+ "properties": {
44793
+ "client_id": {
44794
+ "type": "string",
44795
+ "description": "The confidential client of the resource server allowed to exchange."
44796
+ },
44797
+ "audience": {
44798
+ "type": "string",
44799
+ "description": "Identifier of the registered API the new token is for."
44800
+ }
44801
+ }
44802
+ },
44309
44803
  "skip_consent": {
44310
44804
  "type": "boolean",
44311
44805
  "description": "When true, skip the consent prompt for first-party clients."
@@ -44437,327 +44931,54 @@
44437
44931
  "type": "boolean",
44438
44932
  "description": "When true, the API is eligible to be the target of a `refresh_token` (i.e. clients can request `offline_access` against it)."
44439
44933
  },
44440
- "skip_consent": {
44441
- "type": "boolean",
44442
- "description": "When true, the consent prompt is skipped for first-party clients (clients owned by the same tenant as the API)."
44443
- },
44444
- "include_teams_in_access_token": {
44445
- "type": "boolean",
44446
- "description": "When true, access_tokens issued for this API carry a `teams` claim listing the slugs of the teams the subject is a member of within the tenant."
44447
- },
44448
- "include_roles_in_access_token": {
44449
- "type": "boolean",
44450
- "description": "When true, access_tokens issued for this API carry a `roles` claim listing the names of the roles the subject holds across their team memberships within the tenant."
44451
- },
44452
- "include_teams_in_id_token": {
44453
- "type": "boolean",
44454
- "description": "When true, id_tokens issued together with an access_token for this API carry a `teams` claim with the subject team slugs. The id_token only sees the flag when the client requested `audience=` so this API is resolved at issuance time."
44455
- },
44456
- "include_roles_in_id_token": {
44457
- "type": "boolean",
44458
- "description": "When true, id_tokens issued together with an access_token for this API carry a `roles` claim with the subject role names. Same audience caveat as `include_teams_in_id_token`."
44459
- },
44460
- "account": {
44461
- "type": "string",
44462
- "description": "Object is related with this account"
44463
- },
44464
- "metadata": {
44465
- "type": "object",
44466
- "properties": {},
44467
- "additionalProperties": true,
44468
- "description": "ApiMetadata",
44469
- "default": {}
44470
- },
44471
- "createdAt": {
44472
- "type": "string",
44473
- "description": "Api creation date"
44474
- },
44475
- "updatedAt": {
44476
- "type": "string",
44477
- "description": "Api updated date"
44478
- }
44479
- },
44480
- "description": "Api"
44481
- }
44482
- }
44483
- }
44484
- },
44485
- "400": {
44486
- "description": "`already_exists` — A resource with the same unique field already exists (for a user, usually `email`). `details.fields` names the field.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
44487
- "content": {
44488
- "application/json": {
44489
- "schema": {
44490
- "allOf": [
44491
- {
44492
- "$ref": "#/components/schemas/ErrorResponse"
44493
- },
44494
- {
44495
- "type": "object",
44496
- "properties": {
44497
- "error_code": {
44498
- "type": "string",
44499
- "enum": [
44500
- "already_exists",
44501
- "validation_error"
44502
- ]
44503
- }
44504
- }
44505
- }
44506
- ]
44507
- }
44508
- }
44509
- }
44510
- },
44511
- "401": {
44512
- "description": "`unauthorized` — The request carries no valid credentials.",
44513
- "content": {
44514
- "application/json": {
44515
- "schema": {
44516
- "allOf": [
44517
- {
44518
- "$ref": "#/components/schemas/ErrorResponse"
44519
- },
44520
- {
44521
- "type": "object",
44522
- "properties": {
44523
- "error_code": {
44524
- "type": "string",
44525
- "enum": [
44526
- "unauthorized"
44527
- ]
44528
- }
44529
- }
44530
- }
44531
- ]
44532
- }
44533
- }
44534
- }
44535
- },
44536
- "403": {
44537
- "description": "`forbidden` — The credentials are valid but do not allow this operation.\n\n`insufficient_scope` — The token lacks a scope this operation requires. `message` names it.\n\n`user_suspended` — The user is suspended and cannot sign in or be modified.",
44538
- "content": {
44539
- "application/json": {
44540
- "schema": {
44541
- "allOf": [
44542
- {
44543
- "$ref": "#/components/schemas/ErrorResponse"
44544
- },
44545
- {
44934
+ "consent_options": {
44546
44935
  "type": "object",
44936
+ "required": [
44937
+ "claim",
44938
+ "label",
44939
+ "url",
44940
+ "audience"
44941
+ ],
44547
44942
  "properties": {
44548
- "error_code": {
44943
+ "claim": {
44549
44944
  "type": "string",
44550
- "enum": [
44551
- "forbidden",
44552
- "insufficient_scope",
44553
- "user_suspended"
44554
- ]
44555
- }
44556
- }
44557
- }
44558
- ]
44559
- }
44560
- }
44561
- }
44562
- },
44563
- "404": {
44564
- "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
44565
- "content": {
44566
- "application/json": {
44567
- "schema": {
44568
- "allOf": [
44569
- {
44570
- "$ref": "#/components/schemas/ErrorResponse"
44571
- },
44572
- {
44573
- "type": "object",
44574
- "properties": {
44575
- "error_code": {
44945
+ "pattern": "^[a-z][a-z0-9_]{0,31}$",
44946
+ "description": "Access token claim that carries the chosen id."
44947
+ },
44948
+ "label": {
44576
44949
  "type": "string",
44577
- "enum": [
44578
- "account_not_found"
44579
- ]
44580
- }
44581
- }
44582
- }
44583
- ]
44584
- }
44585
- }
44586
- }
44587
- },
44588
- "429": {
44589
- "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
44590
- "content": {
44591
- "application/json": {
44592
- "schema": {
44593
- "allOf": [
44594
- {
44595
- "$ref": "#/components/schemas/ErrorResponse"
44596
- },
44597
- {
44598
- "type": "object",
44599
- "properties": {
44600
- "error_code": {
44950
+ "maxLength": 60,
44951
+ "description": "What the screen asks for, e.g. \"Project\"."
44952
+ },
44953
+ "url": {
44601
44954
  "type": "string",
44602
- "enum": [
44603
- "too_many_requests"
44604
- ]
44605
- }
44606
- }
44607
- }
44608
- ]
44609
- }
44610
- }
44611
- }
44612
- },
44613
- "500": {
44614
- "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
44615
- "content": {
44616
- "application/json": {
44617
- "schema": {
44618
- "allOf": [
44619
- {
44620
- "$ref": "#/components/schemas/ErrorResponse"
44621
- },
44622
- {
44623
- "type": "object",
44624
- "properties": {
44625
- "error_code": {
44955
+ "pattern": "^https://",
44956
+ "description": "GET endpoint of the resource server that lists the choices."
44957
+ },
44958
+ "audience": {
44626
44959
  "type": "string",
44627
- "enum": [
44628
- "internal_error"
44629
- ]
44960
+ "description": "Identifier of a registered API the listing token is issued for (usually the resource server behind `url`)."
44630
44961
  }
44631
- }
44632
- }
44633
- ]
44634
- }
44635
- }
44636
- }
44637
- }
44638
- }
44639
- }
44640
- },
44641
- "/api/{api_id}": {
44642
- "get": {
44643
- "operationId": "api/get",
44644
- "summary": "Get Api",
44645
- "tags": [
44646
- "api"
44647
- ],
44648
- "description": "Get Api",
44649
- "parameters": [
44650
- {
44651
- "schema": {
44652
- "type": "string"
44653
- },
44654
- "in": "path",
44655
- "name": "api_id",
44656
- "required": true
44657
- }
44658
- ],
44659
- "security": [
44660
- {
44661
- "bearerAuth": []
44662
- }
44663
- ],
44664
- "responses": {
44665
- "200": {
44666
- "description": "Api",
44667
- "content": {
44668
- "application/json": {
44669
- "schema": {
44670
- "type": "object",
44671
- "required": [
44672
- "id",
44673
- "name",
44674
- "slug",
44675
- "identifier",
44676
- "permissions",
44677
- "signing_alg",
44678
- "token_dialect",
44679
- "token_lifetime",
44680
- "enforce_policies",
44681
- "allow_offline_access",
44682
- "skip_consent",
44683
- "include_teams_in_access_token",
44684
- "include_roles_in_access_token",
44685
- "include_teams_in_id_token",
44686
- "include_roles_in_id_token",
44687
- "account",
44688
- "createdAt"
44689
- ],
44690
- "properties": {
44691
- "id": {
44692
- "type": "string",
44693
- "description": "Api ID"
44694
- },
44695
- "name": {
44696
- "type": "string",
44697
- "description": "Human-readable name for the API. Shown in the dashboard and consent prompts.",
44698
- "example": "My Backend API"
44699
- },
44700
- "slug": {
44701
- "type": "string",
44702
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant."
44703
- },
44704
- "identifier": {
44705
- "type": "string",
44706
- "description": "Audience URL that clients pass as `audience=` when requesting a token for this API. Becomes the `aud` claim in the issued access_token. Immutable after creation and unique within the tenant.",
44707
- "example": "https://api.faable.com"
44708
- },
44709
- "description": {
44710
- "type": "string",
44711
- "description": "Optional human-readable description of the API."
44712
- },
44713
- "permissions": {
44714
- "type": "array",
44715
- "items": {
44716
- "$ref": "#/components/schemas/Permission"
44717
44962
  },
44718
- "description": "Set of permissions (scopes) this API exposes. When a token is issued with `audience=identifier`, the requested `scope` is intersected with this list to populate the `permissions` claim."
44963
+ "nullable": true
44719
44964
  },
44720
- "signing_alg": {
44721
- "anyOf": [
44722
- {
44723
- "type": "string",
44724
- "enum": [
44725
- "RS256"
44726
- ]
44727
- }
44965
+ "delegation": {
44966
+ "type": "object",
44967
+ "required": [
44968
+ "client_id",
44969
+ "audience"
44728
44970
  ],
44729
- "description": "JWA algorithm used to sign access_tokens issued for this API. Currently only RS256 (the account keystore default) is implemented."
44730
- },
44731
- "token_dialect": {
44732
- "anyOf": [
44733
- {
44971
+ "properties": {
44972
+ "client_id": {
44734
44973
  "type": "string",
44735
- "enum": [
44736
- "access_token"
44737
- ]
44974
+ "description": "The confidential client of the resource server allowed to exchange."
44738
44975
  },
44739
- {
44976
+ "audience": {
44740
44977
  "type": "string",
44741
- "enum": [
44742
- "access_token_authz"
44743
- ]
44978
+ "description": "Identifier of the registered API the new token is for."
44744
44979
  }
44745
- ],
44746
- "description": "Shape of access_tokens issued for this API. `access_token` emits the standard OAuth2 token. `access_token_authz` additionally embeds a `permissions` claim listing the permissions granted to the subject for this API."
44747
- },
44748
- "token_lifetime": {
44749
- "type": "integer",
44750
- "description": "Access_token lifetime in seconds. Default 86400 (24h). Applied at token issuance time (overrides the generic default).",
44751
- "minimum": 60,
44752
- "maximum": 2592000
44753
- },
44754
- "enforce_policies": {
44755
- "type": "boolean",
44756
- "description": "When true, only scopes that match a permission in `permissions` are forwarded into the access_token. When false, requested scopes are echoed back verbatim with no filtering."
44757
- },
44758
- "allow_offline_access": {
44759
- "type": "boolean",
44760
- "description": "When true, the API is eligible to be the target of a `refresh_token` (i.e. clients can request `offline_access` against it)."
44980
+ },
44981
+ "nullable": true
44761
44982
  },
44762
44983
  "skip_consent": {
44763
44984
  "type": "boolean",
@@ -44805,7 +45026,7 @@
44805
45026
  }
44806
45027
  },
44807
45028
  "400": {
44808
- "description": "`invalid_id` — The id in the path is not a valid id for this resource.\n\n`invalid_expand` — An `?expand=` path is not allowed on this resource.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
45029
+ "description": "`already_exists` — A resource with the same unique field already exists (for a user, usually `email`). `details.fields` names the field.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
44809
45030
  "content": {
44810
45031
  "application/json": {
44811
45032
  "schema": {
@@ -44819,8 +45040,7 @@
44819
45040
  "error_code": {
44820
45041
  "type": "string",
44821
45042
  "enum": [
44822
- "invalid_id",
44823
- "invalid_expand",
45043
+ "already_exists",
44824
45044
  "validation_error"
44825
45045
  ]
44826
45046
  }
@@ -44884,7 +45104,7 @@
44884
45104
  }
44885
45105
  },
44886
45106
  "404": {
44887
- "description": "`not_found` — The resource does not exist in this account.\n\n`account_not_found` — No Auth Account matches the request (domain, header or token).",
45107
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
44888
45108
  "content": {
44889
45109
  "application/json": {
44890
45110
  "schema": {
@@ -44898,7 +45118,6 @@
44898
45118
  "error_code": {
44899
45119
  "type": "string",
44900
45120
  "enum": [
44901
- "not_found",
44902
45121
  "account_not_found"
44903
45122
  ]
44904
45123
  }
@@ -44960,106 +45179,16 @@
44960
45179
  }
44961
45180
  }
44962
45181
  }
44963
- },
44964
- "post": {
44965
- "operationId": "api/update",
44966
- "summary": "Update Api",
45182
+ }
45183
+ },
45184
+ "/api/{api_id}": {
45185
+ "get": {
45186
+ "operationId": "api/get",
45187
+ "summary": "Get Api",
44967
45188
  "tags": [
44968
45189
  "api"
44969
45190
  ],
44970
- "description": "Update Api",
44971
- "requestBody": {
44972
- "required": true,
44973
- "content": {
44974
- "application/json": {
44975
- "schema": {
44976
- "type": "object",
44977
- "properties": {
44978
- "name": {
44979
- "type": "string",
44980
- "description": "Human-readable name for the API."
44981
- },
44982
- "description": {
44983
- "type": "string",
44984
- "description": "Optional human-readable description of the API."
44985
- },
44986
- "permissions": {
44987
- "type": "array",
44988
- "items": {
44989
- "$ref": "#/components/schemas/PermissionCreate"
44990
- },
44991
- "description": "Replaces the full permissions list. Tokens issued AFTER the update will use the new list; tokens already in circulation are unchanged."
44992
- },
44993
- "signing_alg": {
44994
- "anyOf": [
44995
- {
44996
- "type": "string",
44997
- "enum": [
44998
- "RS256"
44999
- ]
45000
- }
45001
- ],
45002
- "description": "JWA algorithm used to sign access_tokens issued for this API. Currently only RS256 (the account keystore default) is implemented."
45003
- },
45004
- "token_dialect": {
45005
- "anyOf": [
45006
- {
45007
- "type": "string",
45008
- "enum": [
45009
- "access_token"
45010
- ]
45011
- },
45012
- {
45013
- "type": "string",
45014
- "enum": [
45015
- "access_token_authz"
45016
- ]
45017
- }
45018
- ],
45019
- "description": "Shape of access_tokens issued for this API. `access_token` emits the standard OAuth2 token. `access_token_authz` additionally embeds a `permissions` claim listing the permissions granted to the subject for this API."
45020
- },
45021
- "token_lifetime": {
45022
- "type": "integer",
45023
- "description": "Access_token lifetime in seconds.",
45024
- "minimum": 60,
45025
- "maximum": 2592000
45026
- },
45027
- "enforce_policies": {
45028
- "type": "boolean",
45029
- "description": "When true, requested scopes are filtered against `permissions` at token issuance."
45030
- },
45031
- "allow_offline_access": {
45032
- "type": "boolean",
45033
- "description": "When true, clients can request `offline_access` and receive a refresh_token for this API."
45034
- },
45035
- "skip_consent": {
45036
- "type": "boolean",
45037
- "description": "When true, skip the consent prompt for first-party clients."
45038
- },
45039
- "include_teams_in_access_token": {
45040
- "type": "boolean",
45041
- "description": "When true, access_tokens issued for this API carry a `teams` claim with the subject team slugs."
45042
- },
45043
- "include_roles_in_access_token": {
45044
- "type": "boolean",
45045
- "description": "When true, access_tokens issued for this API carry a `roles` claim with the subject role names."
45046
- },
45047
- "include_teams_in_id_token": {
45048
- "type": "boolean",
45049
- "description": "When true, id_tokens issued together with an access_token for this API carry a `teams` claim with the subject team slugs."
45050
- },
45051
- "include_roles_in_id_token": {
45052
- "type": "boolean",
45053
- "description": "When true, id_tokens issued together with an access_token for this API carry a `roles` claim with the subject role names."
45054
- }
45055
- },
45056
- "additionalProperties": false,
45057
- "description": "Partial update for an Api. `identifier` is immutable and not present here; recreate the API if you need to change it."
45058
- }
45059
- }
45060
- },
45061
- "description": "Partial update for an Api. `identifier` is immutable and not present here; recreate the API if you need to change it."
45062
- },
45191
+ "description": "Get Api",
45063
45192
  "parameters": [
45064
45193
  {
45065
45194
  "schema": {
@@ -45173,6 +45302,55 @@
45173
45302
  "type": "boolean",
45174
45303
  "description": "When true, the API is eligible to be the target of a `refresh_token` (i.e. clients can request `offline_access` against it)."
45175
45304
  },
45305
+ "consent_options": {
45306
+ "type": "object",
45307
+ "required": [
45308
+ "claim",
45309
+ "label",
45310
+ "url",
45311
+ "audience"
45312
+ ],
45313
+ "properties": {
45314
+ "claim": {
45315
+ "type": "string",
45316
+ "pattern": "^[a-z][a-z0-9_]{0,31}$",
45317
+ "description": "Access token claim that carries the chosen id."
45318
+ },
45319
+ "label": {
45320
+ "type": "string",
45321
+ "maxLength": 60,
45322
+ "description": "What the screen asks for, e.g. \"Project\"."
45323
+ },
45324
+ "url": {
45325
+ "type": "string",
45326
+ "pattern": "^https://",
45327
+ "description": "GET endpoint of the resource server that lists the choices."
45328
+ },
45329
+ "audience": {
45330
+ "type": "string",
45331
+ "description": "Identifier of a registered API the listing token is issued for (usually the resource server behind `url`)."
45332
+ }
45333
+ },
45334
+ "nullable": true
45335
+ },
45336
+ "delegation": {
45337
+ "type": "object",
45338
+ "required": [
45339
+ "client_id",
45340
+ "audience"
45341
+ ],
45342
+ "properties": {
45343
+ "client_id": {
45344
+ "type": "string",
45345
+ "description": "The confidential client of the resource server allowed to exchange."
45346
+ },
45347
+ "audience": {
45348
+ "type": "string",
45349
+ "description": "Identifier of the registered API the new token is for."
45350
+ }
45351
+ },
45352
+ "nullable": true
45353
+ },
45176
45354
  "skip_consent": {
45177
45355
  "type": "boolean",
45178
45356
  "description": "When true, the consent prompt is skipped for first-party clients (clients owned by the same tenant as the API)."
@@ -45219,7 +45397,7 @@
45219
45397
  }
45220
45398
  },
45221
45399
  "400": {
45222
- "description": "`invalid_id` — The id in the path is not a valid id for this resource.\n\n`already_exists` — A resource with the same unique field already exists (for a user, usually `email`). `details.fields` names the field.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
45400
+ "description": "`invalid_id` — The id in the path is not a valid id for this resource.\n\n`invalid_expand` — An `?expand=` path is not allowed on this resource.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
45223
45401
  "content": {
45224
45402
  "application/json": {
45225
45403
  "schema": {
@@ -45234,7 +45412,7 @@
45234
45412
  "type": "string",
45235
45413
  "enum": [
45236
45414
  "invalid_id",
45237
- "already_exists",
45415
+ "invalid_expand",
45238
45416
  "validation_error"
45239
45417
  ]
45240
45418
  }
@@ -45375,13 +45553,154 @@
45375
45553
  }
45376
45554
  }
45377
45555
  },
45378
- "delete": {
45379
- "operationId": "api/delete",
45380
- "summary": "Delete Api",
45556
+ "post": {
45557
+ "operationId": "api/update",
45558
+ "summary": "Update Api",
45381
45559
  "tags": [
45382
45560
  "api"
45383
45561
  ],
45384
- "description": "Delete Api",
45562
+ "description": "Update Api",
45563
+ "requestBody": {
45564
+ "required": true,
45565
+ "content": {
45566
+ "application/json": {
45567
+ "schema": {
45568
+ "type": "object",
45569
+ "properties": {
45570
+ "name": {
45571
+ "type": "string",
45572
+ "description": "Human-readable name for the API."
45573
+ },
45574
+ "description": {
45575
+ "type": "string",
45576
+ "description": "Optional human-readable description of the API."
45577
+ },
45578
+ "permissions": {
45579
+ "type": "array",
45580
+ "items": {
45581
+ "$ref": "#/components/schemas/PermissionCreate"
45582
+ },
45583
+ "description": "Replaces the full permissions list. Tokens issued AFTER the update will use the new list; tokens already in circulation are unchanged."
45584
+ },
45585
+ "signing_alg": {
45586
+ "anyOf": [
45587
+ {
45588
+ "type": "string",
45589
+ "enum": [
45590
+ "RS256"
45591
+ ]
45592
+ }
45593
+ ],
45594
+ "description": "JWA algorithm used to sign access_tokens issued for this API. Currently only RS256 (the account keystore default) is implemented."
45595
+ },
45596
+ "token_dialect": {
45597
+ "anyOf": [
45598
+ {
45599
+ "type": "string",
45600
+ "enum": [
45601
+ "access_token"
45602
+ ]
45603
+ },
45604
+ {
45605
+ "type": "string",
45606
+ "enum": [
45607
+ "access_token_authz"
45608
+ ]
45609
+ }
45610
+ ],
45611
+ "description": "Shape of access_tokens issued for this API. `access_token` emits the standard OAuth2 token. `access_token_authz` additionally embeds a `permissions` claim listing the permissions granted to the subject for this API."
45612
+ },
45613
+ "token_lifetime": {
45614
+ "type": "integer",
45615
+ "description": "Access_token lifetime in seconds.",
45616
+ "minimum": 60,
45617
+ "maximum": 2592000
45618
+ },
45619
+ "enforce_policies": {
45620
+ "type": "boolean",
45621
+ "description": "When true, requested scopes are filtered against `permissions` at token issuance."
45622
+ },
45623
+ "allow_offline_access": {
45624
+ "type": "boolean",
45625
+ "description": "When true, clients can request `offline_access` and receive a refresh_token for this API."
45626
+ },
45627
+ "consent_options": {
45628
+ "type": "object",
45629
+ "required": [
45630
+ "claim",
45631
+ "label",
45632
+ "url",
45633
+ "audience"
45634
+ ],
45635
+ "properties": {
45636
+ "claim": {
45637
+ "type": "string",
45638
+ "pattern": "^[a-z][a-z0-9_]{0,31}$",
45639
+ "description": "Access token claim that carries the chosen id."
45640
+ },
45641
+ "label": {
45642
+ "type": "string",
45643
+ "maxLength": 60,
45644
+ "description": "What the screen asks for, e.g. \"Project\"."
45645
+ },
45646
+ "url": {
45647
+ "type": "string",
45648
+ "pattern": "^https://",
45649
+ "description": "GET endpoint of the resource server that lists the choices."
45650
+ },
45651
+ "audience": {
45652
+ "type": "string",
45653
+ "description": "Identifier of a registered API the listing token is issued for (usually the resource server behind `url`)."
45654
+ }
45655
+ },
45656
+ "nullable": true
45657
+ },
45658
+ "delegation": {
45659
+ "type": "object",
45660
+ "required": [
45661
+ "client_id",
45662
+ "audience"
45663
+ ],
45664
+ "properties": {
45665
+ "client_id": {
45666
+ "type": "string",
45667
+ "description": "The confidential client of the resource server allowed to exchange."
45668
+ },
45669
+ "audience": {
45670
+ "type": "string",
45671
+ "description": "Identifier of the registered API the new token is for."
45672
+ }
45673
+ },
45674
+ "nullable": true
45675
+ },
45676
+ "skip_consent": {
45677
+ "type": "boolean",
45678
+ "description": "When true, skip the consent prompt for first-party clients."
45679
+ },
45680
+ "include_teams_in_access_token": {
45681
+ "type": "boolean",
45682
+ "description": "When true, access_tokens issued for this API carry a `teams` claim with the subject team slugs."
45683
+ },
45684
+ "include_roles_in_access_token": {
45685
+ "type": "boolean",
45686
+ "description": "When true, access_tokens issued for this API carry a `roles` claim with the subject role names."
45687
+ },
45688
+ "include_teams_in_id_token": {
45689
+ "type": "boolean",
45690
+ "description": "When true, id_tokens issued together with an access_token for this API carry a `teams` claim with the subject team slugs."
45691
+ },
45692
+ "include_roles_in_id_token": {
45693
+ "type": "boolean",
45694
+ "description": "When true, id_tokens issued together with an access_token for this API carry a `roles` claim with the subject role names."
45695
+ }
45696
+ },
45697
+ "additionalProperties": false,
45698
+ "description": "Partial update for an Api. `identifier` is immutable and not present here; recreate the API if you need to change it."
45699
+ }
45700
+ }
45701
+ },
45702
+ "description": "Partial update for an Api. `identifier` is immutable and not present here; recreate the API if you need to change it."
45703
+ },
45385
45704
  "parameters": [
45386
45705
  {
45387
45706
  "schema": {
@@ -45495,6 +45814,426 @@
45495
45814
  "type": "boolean",
45496
45815
  "description": "When true, the API is eligible to be the target of a `refresh_token` (i.e. clients can request `offline_access` against it)."
45497
45816
  },
45817
+ "consent_options": {
45818
+ "type": "object",
45819
+ "required": [
45820
+ "claim",
45821
+ "label",
45822
+ "url",
45823
+ "audience"
45824
+ ],
45825
+ "properties": {
45826
+ "claim": {
45827
+ "type": "string",
45828
+ "pattern": "^[a-z][a-z0-9_]{0,31}$",
45829
+ "description": "Access token claim that carries the chosen id."
45830
+ },
45831
+ "label": {
45832
+ "type": "string",
45833
+ "maxLength": 60,
45834
+ "description": "What the screen asks for, e.g. \"Project\"."
45835
+ },
45836
+ "url": {
45837
+ "type": "string",
45838
+ "pattern": "^https://",
45839
+ "description": "GET endpoint of the resource server that lists the choices."
45840
+ },
45841
+ "audience": {
45842
+ "type": "string",
45843
+ "description": "Identifier of a registered API the listing token is issued for (usually the resource server behind `url`)."
45844
+ }
45845
+ },
45846
+ "nullable": true
45847
+ },
45848
+ "delegation": {
45849
+ "type": "object",
45850
+ "required": [
45851
+ "client_id",
45852
+ "audience"
45853
+ ],
45854
+ "properties": {
45855
+ "client_id": {
45856
+ "type": "string",
45857
+ "description": "The confidential client of the resource server allowed to exchange."
45858
+ },
45859
+ "audience": {
45860
+ "type": "string",
45861
+ "description": "Identifier of the registered API the new token is for."
45862
+ }
45863
+ },
45864
+ "nullable": true
45865
+ },
45866
+ "skip_consent": {
45867
+ "type": "boolean",
45868
+ "description": "When true, the consent prompt is skipped for first-party clients (clients owned by the same tenant as the API)."
45869
+ },
45870
+ "include_teams_in_access_token": {
45871
+ "type": "boolean",
45872
+ "description": "When true, access_tokens issued for this API carry a `teams` claim listing the slugs of the teams the subject is a member of within the tenant."
45873
+ },
45874
+ "include_roles_in_access_token": {
45875
+ "type": "boolean",
45876
+ "description": "When true, access_tokens issued for this API carry a `roles` claim listing the names of the roles the subject holds across their team memberships within the tenant."
45877
+ },
45878
+ "include_teams_in_id_token": {
45879
+ "type": "boolean",
45880
+ "description": "When true, id_tokens issued together with an access_token for this API carry a `teams` claim with the subject team slugs. The id_token only sees the flag when the client requested `audience=` so this API is resolved at issuance time."
45881
+ },
45882
+ "include_roles_in_id_token": {
45883
+ "type": "boolean",
45884
+ "description": "When true, id_tokens issued together with an access_token for this API carry a `roles` claim with the subject role names. Same audience caveat as `include_teams_in_id_token`."
45885
+ },
45886
+ "account": {
45887
+ "type": "string",
45888
+ "description": "Object is related with this account"
45889
+ },
45890
+ "metadata": {
45891
+ "type": "object",
45892
+ "properties": {},
45893
+ "additionalProperties": true,
45894
+ "description": "ApiMetadata",
45895
+ "default": {}
45896
+ },
45897
+ "createdAt": {
45898
+ "type": "string",
45899
+ "description": "Api creation date"
45900
+ },
45901
+ "updatedAt": {
45902
+ "type": "string",
45903
+ "description": "Api updated date"
45904
+ }
45905
+ },
45906
+ "description": "Api"
45907
+ }
45908
+ }
45909
+ }
45910
+ },
45911
+ "400": {
45912
+ "description": "`invalid_id` — The id in the path is not a valid id for this resource.\n\n`already_exists` — A resource with the same unique field already exists (for a user, usually `email`). `details.fields` names the field.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
45913
+ "content": {
45914
+ "application/json": {
45915
+ "schema": {
45916
+ "allOf": [
45917
+ {
45918
+ "$ref": "#/components/schemas/ErrorResponse"
45919
+ },
45920
+ {
45921
+ "type": "object",
45922
+ "properties": {
45923
+ "error_code": {
45924
+ "type": "string",
45925
+ "enum": [
45926
+ "invalid_id",
45927
+ "already_exists",
45928
+ "validation_error"
45929
+ ]
45930
+ }
45931
+ }
45932
+ }
45933
+ ]
45934
+ }
45935
+ }
45936
+ }
45937
+ },
45938
+ "401": {
45939
+ "description": "`unauthorized` — The request carries no valid credentials.",
45940
+ "content": {
45941
+ "application/json": {
45942
+ "schema": {
45943
+ "allOf": [
45944
+ {
45945
+ "$ref": "#/components/schemas/ErrorResponse"
45946
+ },
45947
+ {
45948
+ "type": "object",
45949
+ "properties": {
45950
+ "error_code": {
45951
+ "type": "string",
45952
+ "enum": [
45953
+ "unauthorized"
45954
+ ]
45955
+ }
45956
+ }
45957
+ }
45958
+ ]
45959
+ }
45960
+ }
45961
+ }
45962
+ },
45963
+ "403": {
45964
+ "description": "`forbidden` — The credentials are valid but do not allow this operation.\n\n`insufficient_scope` — The token lacks a scope this operation requires. `message` names it.\n\n`user_suspended` — The user is suspended and cannot sign in or be modified.",
45965
+ "content": {
45966
+ "application/json": {
45967
+ "schema": {
45968
+ "allOf": [
45969
+ {
45970
+ "$ref": "#/components/schemas/ErrorResponse"
45971
+ },
45972
+ {
45973
+ "type": "object",
45974
+ "properties": {
45975
+ "error_code": {
45976
+ "type": "string",
45977
+ "enum": [
45978
+ "forbidden",
45979
+ "insufficient_scope",
45980
+ "user_suspended"
45981
+ ]
45982
+ }
45983
+ }
45984
+ }
45985
+ ]
45986
+ }
45987
+ }
45988
+ }
45989
+ },
45990
+ "404": {
45991
+ "description": "`not_found` — The resource does not exist in this account.\n\n`account_not_found` — No Auth Account matches the request (domain, header or token).",
45992
+ "content": {
45993
+ "application/json": {
45994
+ "schema": {
45995
+ "allOf": [
45996
+ {
45997
+ "$ref": "#/components/schemas/ErrorResponse"
45998
+ },
45999
+ {
46000
+ "type": "object",
46001
+ "properties": {
46002
+ "error_code": {
46003
+ "type": "string",
46004
+ "enum": [
46005
+ "not_found",
46006
+ "account_not_found"
46007
+ ]
46008
+ }
46009
+ }
46010
+ }
46011
+ ]
46012
+ }
46013
+ }
46014
+ }
46015
+ },
46016
+ "429": {
46017
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
46018
+ "content": {
46019
+ "application/json": {
46020
+ "schema": {
46021
+ "allOf": [
46022
+ {
46023
+ "$ref": "#/components/schemas/ErrorResponse"
46024
+ },
46025
+ {
46026
+ "type": "object",
46027
+ "properties": {
46028
+ "error_code": {
46029
+ "type": "string",
46030
+ "enum": [
46031
+ "too_many_requests"
46032
+ ]
46033
+ }
46034
+ }
46035
+ }
46036
+ ]
46037
+ }
46038
+ }
46039
+ }
46040
+ },
46041
+ "500": {
46042
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
46043
+ "content": {
46044
+ "application/json": {
46045
+ "schema": {
46046
+ "allOf": [
46047
+ {
46048
+ "$ref": "#/components/schemas/ErrorResponse"
46049
+ },
46050
+ {
46051
+ "type": "object",
46052
+ "properties": {
46053
+ "error_code": {
46054
+ "type": "string",
46055
+ "enum": [
46056
+ "internal_error"
46057
+ ]
46058
+ }
46059
+ }
46060
+ }
46061
+ ]
46062
+ }
46063
+ }
46064
+ }
46065
+ }
46066
+ }
46067
+ },
46068
+ "delete": {
46069
+ "operationId": "api/delete",
46070
+ "summary": "Delete Api",
46071
+ "tags": [
46072
+ "api"
46073
+ ],
46074
+ "description": "Delete Api",
46075
+ "parameters": [
46076
+ {
46077
+ "schema": {
46078
+ "type": "string"
46079
+ },
46080
+ "in": "path",
46081
+ "name": "api_id",
46082
+ "required": true
46083
+ }
46084
+ ],
46085
+ "security": [
46086
+ {
46087
+ "bearerAuth": []
46088
+ }
46089
+ ],
46090
+ "responses": {
46091
+ "200": {
46092
+ "description": "Api",
46093
+ "content": {
46094
+ "application/json": {
46095
+ "schema": {
46096
+ "type": "object",
46097
+ "required": [
46098
+ "id",
46099
+ "name",
46100
+ "slug",
46101
+ "identifier",
46102
+ "permissions",
46103
+ "signing_alg",
46104
+ "token_dialect",
46105
+ "token_lifetime",
46106
+ "enforce_policies",
46107
+ "allow_offline_access",
46108
+ "skip_consent",
46109
+ "include_teams_in_access_token",
46110
+ "include_roles_in_access_token",
46111
+ "include_teams_in_id_token",
46112
+ "include_roles_in_id_token",
46113
+ "account",
46114
+ "createdAt"
46115
+ ],
46116
+ "properties": {
46117
+ "id": {
46118
+ "type": "string",
46119
+ "description": "Api ID"
46120
+ },
46121
+ "name": {
46122
+ "type": "string",
46123
+ "description": "Human-readable name for the API. Shown in the dashboard and consent prompts.",
46124
+ "example": "My Backend API"
46125
+ },
46126
+ "slug": {
46127
+ "type": "string",
46128
+ "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant."
46129
+ },
46130
+ "identifier": {
46131
+ "type": "string",
46132
+ "description": "Audience URL that clients pass as `audience=` when requesting a token for this API. Becomes the `aud` claim in the issued access_token. Immutable after creation and unique within the tenant.",
46133
+ "example": "https://api.faable.com"
46134
+ },
46135
+ "description": {
46136
+ "type": "string",
46137
+ "description": "Optional human-readable description of the API."
46138
+ },
46139
+ "permissions": {
46140
+ "type": "array",
46141
+ "items": {
46142
+ "$ref": "#/components/schemas/Permission"
46143
+ },
46144
+ "description": "Set of permissions (scopes) this API exposes. When a token is issued with `audience=identifier`, the requested `scope` is intersected with this list to populate the `permissions` claim."
46145
+ },
46146
+ "signing_alg": {
46147
+ "anyOf": [
46148
+ {
46149
+ "type": "string",
46150
+ "enum": [
46151
+ "RS256"
46152
+ ]
46153
+ }
46154
+ ],
46155
+ "description": "JWA algorithm used to sign access_tokens issued for this API. Currently only RS256 (the account keystore default) is implemented."
46156
+ },
46157
+ "token_dialect": {
46158
+ "anyOf": [
46159
+ {
46160
+ "type": "string",
46161
+ "enum": [
46162
+ "access_token"
46163
+ ]
46164
+ },
46165
+ {
46166
+ "type": "string",
46167
+ "enum": [
46168
+ "access_token_authz"
46169
+ ]
46170
+ }
46171
+ ],
46172
+ "description": "Shape of access_tokens issued for this API. `access_token` emits the standard OAuth2 token. `access_token_authz` additionally embeds a `permissions` claim listing the permissions granted to the subject for this API."
46173
+ },
46174
+ "token_lifetime": {
46175
+ "type": "integer",
46176
+ "description": "Access_token lifetime in seconds. Default 86400 (24h). Applied at token issuance time (overrides the generic default).",
46177
+ "minimum": 60,
46178
+ "maximum": 2592000
46179
+ },
46180
+ "enforce_policies": {
46181
+ "type": "boolean",
46182
+ "description": "When true, only scopes that match a permission in `permissions` are forwarded into the access_token. When false, requested scopes are echoed back verbatim with no filtering."
46183
+ },
46184
+ "allow_offline_access": {
46185
+ "type": "boolean",
46186
+ "description": "When true, the API is eligible to be the target of a `refresh_token` (i.e. clients can request `offline_access` against it)."
46187
+ },
46188
+ "consent_options": {
46189
+ "type": "object",
46190
+ "required": [
46191
+ "claim",
46192
+ "label",
46193
+ "url",
46194
+ "audience"
46195
+ ],
46196
+ "properties": {
46197
+ "claim": {
46198
+ "type": "string",
46199
+ "pattern": "^[a-z][a-z0-9_]{0,31}$",
46200
+ "description": "Access token claim that carries the chosen id."
46201
+ },
46202
+ "label": {
46203
+ "type": "string",
46204
+ "maxLength": 60,
46205
+ "description": "What the screen asks for, e.g. \"Project\"."
46206
+ },
46207
+ "url": {
46208
+ "type": "string",
46209
+ "pattern": "^https://",
46210
+ "description": "GET endpoint of the resource server that lists the choices."
46211
+ },
46212
+ "audience": {
46213
+ "type": "string",
46214
+ "description": "Identifier of a registered API the listing token is issued for (usually the resource server behind `url`)."
46215
+ }
46216
+ },
46217
+ "nullable": true
46218
+ },
46219
+ "delegation": {
46220
+ "type": "object",
46221
+ "required": [
46222
+ "client_id",
46223
+ "audience"
46224
+ ],
46225
+ "properties": {
46226
+ "client_id": {
46227
+ "type": "string",
46228
+ "description": "The confidential client of the resource server allowed to exchange."
46229
+ },
46230
+ "audience": {
46231
+ "type": "string",
46232
+ "description": "Identifier of the registered API the new token is for."
46233
+ }
46234
+ },
46235
+ "nullable": true
46236
+ },
45498
46237
  "skip_consent": {
45499
46238
  "type": "boolean",
45500
46239
  "description": "When true, the consent prompt is skipped for first-party clients (clients owned by the same tenant as the API)."
@@ -46136,6 +46875,15 @@
46136
46875
  "required": false,
46137
46876
  "description": "Cursor returned by the previous page"
46138
46877
  },
46878
+ {
46879
+ "schema": {
46880
+ "type": "boolean"
46881
+ },
46882
+ "in": "query",
46883
+ "name": "count",
46884
+ "required": false,
46885
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
46886
+ },
46139
46887
  {
46140
46888
  "schema": {
46141
46889
  "type": "string"
@@ -46178,6 +46926,10 @@
46178
46926
  "items": {
46179
46927
  "$ref": "#/components/schemas/Action"
46180
46928
  }
46929
+ },
46930
+ "total": {
46931
+ "type": "integer",
46932
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
46181
46933
  }
46182
46934
  },
46183
46935
  "additionalProperties": false
@@ -50884,6 +51636,15 @@
50884
51636
  "required": false,
50885
51637
  "description": "Cursor returned by the previous page"
50886
51638
  },
51639
+ {
51640
+ "schema": {
51641
+ "type": "boolean"
51642
+ },
51643
+ "in": "query",
51644
+ "name": "count",
51645
+ "required": false,
51646
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
51647
+ },
50887
51648
  {
50888
51649
  "schema": {
50889
51650
  "type": "string"
@@ -50926,6 +51687,10 @@
50926
51687
  "items": {
50927
51688
  "$ref": "#/components/schemas/LoginFlow"
50928
51689
  }
51690
+ },
51691
+ "total": {
51692
+ "type": "integer",
51693
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
50929
51694
  }
50930
51695
  },
50931
51696
  "additionalProperties": false
@@ -54559,6 +55324,15 @@
54559
55324
  "required": false,
54560
55325
  "description": "Exact match on `events`. Equivalent to `?query=events:<value>`."
54561
55326
  },
55327
+ {
55328
+ "schema": {
55329
+ "type": "boolean"
55330
+ },
55331
+ "in": "query",
55332
+ "name": "count",
55333
+ "required": false,
55334
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
55335
+ },
54562
55336
  {
54563
55337
  "schema": {
54564
55338
  "type": "string"
@@ -54601,6 +55375,10 @@
54601
55375
  "items": {
54602
55376
  "$ref": "#/components/schemas/NotificationSubscription"
54603
55377
  }
55378
+ },
55379
+ "total": {
55380
+ "type": "integer",
55381
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
54604
55382
  }
54605
55383
  },
54606
55384
  "additionalProperties": false
@@ -57311,252 +58089,265 @@
57311
58089
  },
57312
58090
  {
57313
58091
  "schema": {
57314
- "type": "string"
57315
- },
57316
- "in": "query",
57317
- "name": "query",
57318
- "required": false,
57319
- "description": "Filter using a FaableQL query"
57320
- },
57321
- {
57322
- "schema": {
57323
- "type": "array",
57324
- "items": {
57325
- "type": "string",
57326
- "enum": [
57327
- "user",
57328
- "client",
57329
- "connection",
57330
- "team",
57331
- "identity"
57332
- ],
57333
- "description": "Allowed expand paths on `log`: `user`, `client`, `connection`, `team`, `identity`."
57334
- },
57335
- "maxItems": 5
58092
+ "type": "boolean"
57336
58093
  },
57337
58094
  "in": "query",
57338
- "name": "expand",
58095
+ "name": "count",
57339
58096
  "required": false,
57340
- "description": "Expand id-only fields in the response. Pass one path per entry (e.g. `?expand=user`)."
58097
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
57341
58098
  },
57342
58099
  {
57343
58100
  "schema": {
57344
- "type": "string",
57345
- "minLength": 1,
57346
- "maxLength": 200
58101
+ "type": "string"
57347
58102
  },
57348
58103
  "in": "query",
57349
- "name": "q",
58104
+ "name": "query",
57350
58105
  "required": false,
57351
- "description": "Full-text search across: `message`."
57352
- }
57353
- ],
57354
- "security": [
57355
- {
57356
- "bearerAuth": []
57357
- }
57358
- ],
57359
- "responses": {
57360
- "200": {
57361
- "description": "Default Response",
57362
- "content": {
57363
- "application/json": {
57364
- "schema": {
57365
- "type": "object",
57366
- "required": [
57367
- "next",
57368
- "results"
57369
- ],
57370
- "properties": {
57371
- "next": {
57372
- "anyOf": [
57373
- {
57374
- "type": "string"
57375
- },
57376
- {
57377
- "type": "null"
57378
- }
57379
- ]
57380
- },
57381
- "results": {
57382
- "type": "array",
57383
- "items": {
57384
- "$ref": "#/components/schemas/Log"
57385
- }
57386
- }
57387
- },
57388
- "additionalProperties": false
57389
- }
57390
- }
57391
- }
57392
- },
57393
- "400": {
57394
- "description": "`invalid_query` — The `?query=` FaableQL expression could not be parsed.\n\n`invalid_expand` — An `?expand=` path is not allowed on this resource.\n\n`search_not_supported` — This resource does not support `?search=`.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
57395
- "content": {
57396
- "application/json": {
57397
- "schema": {
57398
- "allOf": [
57399
- {
57400
- "$ref": "#/components/schemas/ErrorResponse"
57401
- },
57402
- {
57403
- "type": "object",
57404
- "properties": {
57405
- "error_code": {
57406
- "type": "string",
57407
- "enum": [
57408
- "invalid_query",
57409
- "invalid_expand",
57410
- "search_not_supported",
57411
- "validation_error"
57412
- ]
57413
- }
57414
- }
57415
- }
57416
- ]
57417
- }
57418
- }
57419
- }
57420
- },
57421
- "401": {
57422
- "description": "`unauthorized` — The request carries no valid credentials.",
57423
- "content": {
57424
- "application/json": {
57425
- "schema": {
57426
- "allOf": [
57427
- {
57428
- "$ref": "#/components/schemas/ErrorResponse"
57429
- },
57430
- {
57431
- "type": "object",
57432
- "properties": {
57433
- "error_code": {
57434
- "type": "string",
57435
- "enum": [
57436
- "unauthorized"
57437
- ]
57438
- }
57439
- }
57440
- }
57441
- ]
57442
- }
57443
- }
57444
- }
57445
- },
57446
- "403": {
57447
- "description": "`forbidden` — The credentials are valid but do not allow this operation.\n\n`insufficient_scope` — The token lacks a scope this operation requires. `message` names it.\n\n`user_suspended` — The user is suspended and cannot sign in or be modified.",
57448
- "content": {
57449
- "application/json": {
57450
- "schema": {
57451
- "allOf": [
57452
- {
57453
- "$ref": "#/components/schemas/ErrorResponse"
57454
- },
57455
- {
57456
- "type": "object",
57457
- "properties": {
57458
- "error_code": {
57459
- "type": "string",
57460
- "enum": [
57461
- "forbidden",
57462
- "insufficient_scope",
57463
- "user_suspended"
57464
- ]
57465
- }
57466
- }
57467
- }
57468
- ]
57469
- }
57470
- }
57471
- }
57472
- },
57473
- "404": {
57474
- "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
57475
- "content": {
57476
- "application/json": {
57477
- "schema": {
57478
- "allOf": [
57479
- {
57480
- "$ref": "#/components/schemas/ErrorResponse"
57481
- },
57482
- {
57483
- "type": "object",
57484
- "properties": {
57485
- "error_code": {
57486
- "type": "string",
57487
- "enum": [
57488
- "account_not_found"
57489
- ]
57490
- }
57491
- }
57492
- }
57493
- ]
57494
- }
57495
- }
57496
- }
57497
- },
57498
- "429": {
57499
- "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
57500
- "content": {
57501
- "application/json": {
57502
- "schema": {
57503
- "allOf": [
57504
- {
57505
- "$ref": "#/components/schemas/ErrorResponse"
57506
- },
57507
- {
57508
- "type": "object",
57509
- "properties": {
57510
- "error_code": {
57511
- "type": "string",
57512
- "enum": [
57513
- "too_many_requests"
57514
- ]
57515
- }
57516
- }
57517
- }
57518
- ]
57519
- }
57520
- }
57521
- }
58106
+ "description": "Filter using a FaableQL query"
57522
58107
  },
57523
- "500": {
57524
- "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
57525
- "content": {
57526
- "application/json": {
57527
- "schema": {
57528
- "allOf": [
57529
- {
57530
- "$ref": "#/components/schemas/ErrorResponse"
57531
- },
57532
- {
57533
- "type": "object",
57534
- "properties": {
57535
- "error_code": {
57536
- "type": "string",
57537
- "enum": [
57538
- "internal_error"
57539
- ]
57540
- }
57541
- }
57542
- }
57543
- ]
57544
- }
57545
- }
57546
- }
57547
- }
57548
- }
57549
- }
57550
- },
57551
- "/log/{log_id}": {
57552
- "get": {
57553
- "operationId": "log/get",
57554
- "summary": "Get Log",
57555
- "tags": [
57556
- "log"
57557
- ],
57558
- "description": "Get Log",
57559
- "parameters": [
58108
+ {
58109
+ "schema": {
58110
+ "type": "array",
58111
+ "items": {
58112
+ "type": "string",
58113
+ "enum": [
58114
+ "user",
58115
+ "client",
58116
+ "connection",
58117
+ "team",
58118
+ "identity"
58119
+ ],
58120
+ "description": "Allowed expand paths on `log`: `user`, `client`, `connection`, `team`, `identity`."
58121
+ },
58122
+ "maxItems": 5
58123
+ },
58124
+ "in": "query",
58125
+ "name": "expand",
58126
+ "required": false,
58127
+ "description": "Expand id-only fields in the response. Pass one path per entry (e.g. `?expand=user`)."
58128
+ },
58129
+ {
58130
+ "schema": {
58131
+ "type": "string",
58132
+ "minLength": 1,
58133
+ "maxLength": 200
58134
+ },
58135
+ "in": "query",
58136
+ "name": "q",
58137
+ "required": false,
58138
+ "description": "Full-text search across: `message`."
58139
+ }
58140
+ ],
58141
+ "security": [
58142
+ {
58143
+ "bearerAuth": []
58144
+ }
58145
+ ],
58146
+ "responses": {
58147
+ "200": {
58148
+ "description": "Default Response",
58149
+ "content": {
58150
+ "application/json": {
58151
+ "schema": {
58152
+ "type": "object",
58153
+ "required": [
58154
+ "next",
58155
+ "results"
58156
+ ],
58157
+ "properties": {
58158
+ "next": {
58159
+ "anyOf": [
58160
+ {
58161
+ "type": "string"
58162
+ },
58163
+ {
58164
+ "type": "null"
58165
+ }
58166
+ ]
58167
+ },
58168
+ "results": {
58169
+ "type": "array",
58170
+ "items": {
58171
+ "$ref": "#/components/schemas/Log"
58172
+ }
58173
+ },
58174
+ "total": {
58175
+ "type": "integer",
58176
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
58177
+ }
58178
+ },
58179
+ "additionalProperties": false
58180
+ }
58181
+ }
58182
+ }
58183
+ },
58184
+ "400": {
58185
+ "description": "`invalid_query` — The `?query=` FaableQL expression could not be parsed.\n\n`invalid_expand` — An `?expand=` path is not allowed on this resource.\n\n`search_not_supported` — This resource does not support `?search=`.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
58186
+ "content": {
58187
+ "application/json": {
58188
+ "schema": {
58189
+ "allOf": [
58190
+ {
58191
+ "$ref": "#/components/schemas/ErrorResponse"
58192
+ },
58193
+ {
58194
+ "type": "object",
58195
+ "properties": {
58196
+ "error_code": {
58197
+ "type": "string",
58198
+ "enum": [
58199
+ "invalid_query",
58200
+ "invalid_expand",
58201
+ "search_not_supported",
58202
+ "validation_error"
58203
+ ]
58204
+ }
58205
+ }
58206
+ }
58207
+ ]
58208
+ }
58209
+ }
58210
+ }
58211
+ },
58212
+ "401": {
58213
+ "description": "`unauthorized` — The request carries no valid credentials.",
58214
+ "content": {
58215
+ "application/json": {
58216
+ "schema": {
58217
+ "allOf": [
58218
+ {
58219
+ "$ref": "#/components/schemas/ErrorResponse"
58220
+ },
58221
+ {
58222
+ "type": "object",
58223
+ "properties": {
58224
+ "error_code": {
58225
+ "type": "string",
58226
+ "enum": [
58227
+ "unauthorized"
58228
+ ]
58229
+ }
58230
+ }
58231
+ }
58232
+ ]
58233
+ }
58234
+ }
58235
+ }
58236
+ },
58237
+ "403": {
58238
+ "description": "`forbidden` — The credentials are valid but do not allow this operation.\n\n`insufficient_scope` — The token lacks a scope this operation requires. `message` names it.\n\n`user_suspended` — The user is suspended and cannot sign in or be modified.",
58239
+ "content": {
58240
+ "application/json": {
58241
+ "schema": {
58242
+ "allOf": [
58243
+ {
58244
+ "$ref": "#/components/schemas/ErrorResponse"
58245
+ },
58246
+ {
58247
+ "type": "object",
58248
+ "properties": {
58249
+ "error_code": {
58250
+ "type": "string",
58251
+ "enum": [
58252
+ "forbidden",
58253
+ "insufficient_scope",
58254
+ "user_suspended"
58255
+ ]
58256
+ }
58257
+ }
58258
+ }
58259
+ ]
58260
+ }
58261
+ }
58262
+ }
58263
+ },
58264
+ "404": {
58265
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
58266
+ "content": {
58267
+ "application/json": {
58268
+ "schema": {
58269
+ "allOf": [
58270
+ {
58271
+ "$ref": "#/components/schemas/ErrorResponse"
58272
+ },
58273
+ {
58274
+ "type": "object",
58275
+ "properties": {
58276
+ "error_code": {
58277
+ "type": "string",
58278
+ "enum": [
58279
+ "account_not_found"
58280
+ ]
58281
+ }
58282
+ }
58283
+ }
58284
+ ]
58285
+ }
58286
+ }
58287
+ }
58288
+ },
58289
+ "429": {
58290
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
58291
+ "content": {
58292
+ "application/json": {
58293
+ "schema": {
58294
+ "allOf": [
58295
+ {
58296
+ "$ref": "#/components/schemas/ErrorResponse"
58297
+ },
58298
+ {
58299
+ "type": "object",
58300
+ "properties": {
58301
+ "error_code": {
58302
+ "type": "string",
58303
+ "enum": [
58304
+ "too_many_requests"
58305
+ ]
58306
+ }
58307
+ }
58308
+ }
58309
+ ]
58310
+ }
58311
+ }
58312
+ }
58313
+ },
58314
+ "500": {
58315
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
58316
+ "content": {
58317
+ "application/json": {
58318
+ "schema": {
58319
+ "allOf": [
58320
+ {
58321
+ "$ref": "#/components/schemas/ErrorResponse"
58322
+ },
58323
+ {
58324
+ "type": "object",
58325
+ "properties": {
58326
+ "error_code": {
58327
+ "type": "string",
58328
+ "enum": [
58329
+ "internal_error"
58330
+ ]
58331
+ }
58332
+ }
58333
+ }
58334
+ ]
58335
+ }
58336
+ }
58337
+ }
58338
+ }
58339
+ }
58340
+ }
58341
+ },
58342
+ "/log/{log_id}": {
58343
+ "get": {
58344
+ "operationId": "log/get",
58345
+ "summary": "Get Log",
58346
+ "tags": [
58347
+ "log"
58348
+ ],
58349
+ "description": "Get Log",
58350
+ "parameters": [
57560
58351
  {
57561
58352
  "schema": {
57562
58353
  "type": "array",
@@ -57998,6 +58789,15 @@
57998
58789
  "required": false,
57999
58790
  "description": "Exact match on `until`. Equivalent to `?query=until:<value>`."
58000
58791
  },
58792
+ {
58793
+ "schema": {
58794
+ "type": "boolean"
58795
+ },
58796
+ "in": "query",
58797
+ "name": "count",
58798
+ "required": false,
58799
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
58800
+ },
58001
58801
  {
58002
58802
  "schema": {
58003
58803
  "type": "string"
@@ -58059,6 +58859,10 @@
58059
58859
  "items": {
58060
58860
  "$ref": "#/components/schemas/Session"
58061
58861
  }
58862
+ },
58863
+ "total": {
58864
+ "type": "integer",
58865
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
58062
58866
  }
58063
58867
  },
58064
58868
  "additionalProperties": false
@@ -59156,6 +59960,15 @@
59156
59960
  "required": false,
59157
59961
  "description": "Cursor returned by the previous page"
59158
59962
  },
59963
+ {
59964
+ "schema": {
59965
+ "type": "boolean"
59966
+ },
59967
+ "in": "query",
59968
+ "name": "count",
59969
+ "required": false,
59970
+ "description": "Also return `total`: the rows matching the whole filter, across every page."
59971
+ },
59159
59972
  {
59160
59973
  "schema": {
59161
59974
  "type": "string"
@@ -59209,6 +60022,10 @@
59209
60022
  "items": {
59210
60023
  "$ref": "#/components/schemas/Customdomain"
59211
60024
  }
60025
+ },
60026
+ "total": {
60027
+ "type": "integer",
60028
+ "description": "Rows matching the whole filter, across every page. Only with `?count=true`."
59212
60029
  }
59213
60030
  },
59214
60031
  "additionalProperties": false
@@ -64417,6 +65234,341 @@
64417
65234
  }
64418
65235
  }
64419
65236
  },
65237
+ "/me/grants": {
65238
+ "get": {
65239
+ "summary": "Apps the signed-in user has connected",
65240
+ "tags": [
65241
+ "account"
65242
+ ],
65243
+ "description": "The live grants of the session user: each app they allowed on the consent screen, what it can do and what they picked (e.g. the project).",
65244
+ "responses": {
65245
+ "200": {
65246
+ "description": "Default Response",
65247
+ "content": {
65248
+ "application/json": {
65249
+ "schema": {
65250
+ "type": "object",
65251
+ "required": [
65252
+ "data"
65253
+ ],
65254
+ "properties": {
65255
+ "data": {
65256
+ "type": "array",
65257
+ "items": {
65258
+ "type": "object",
65259
+ "required": [
65260
+ "id",
65261
+ "client",
65262
+ "resource",
65263
+ "scopes",
65264
+ "created_at"
65265
+ ],
65266
+ "properties": {
65267
+ "id": {
65268
+ "type": "string"
65269
+ },
65270
+ "client": {
65271
+ "type": "object",
65272
+ "required": [
65273
+ "name"
65274
+ ],
65275
+ "properties": {
65276
+ "name": {
65277
+ "type": "string"
65278
+ },
65279
+ "logo_uri": {
65280
+ "type": "string"
65281
+ },
65282
+ "client_uri": {
65283
+ "type": "string"
65284
+ },
65285
+ "metadata_document_url": {
65286
+ "type": "string"
65287
+ }
65288
+ }
65289
+ },
65290
+ "resource": {
65291
+ "type": "string"
65292
+ },
65293
+ "scopes": {
65294
+ "type": "array",
65295
+ "items": {
65296
+ "type": "string"
65297
+ }
65298
+ },
65299
+ "options": {
65300
+ "type": "object",
65301
+ "additionalProperties": {
65302
+ "type": "string"
65303
+ }
65304
+ },
65305
+ "created_at": {
65306
+ "type": "string"
65307
+ },
65308
+ "last_used_at": {
65309
+ "type": "string"
65310
+ }
65311
+ }
65312
+ }
65313
+ }
65314
+ }
65315
+ }
65316
+ }
65317
+ }
65318
+ },
65319
+ "401": {
65320
+ "description": "`not_logged_in` — There is no signed-in session for this request.",
65321
+ "content": {
65322
+ "application/json": {
65323
+ "schema": {
65324
+ "allOf": [
65325
+ {
65326
+ "$ref": "#/components/schemas/ErrorResponse"
65327
+ },
65328
+ {
65329
+ "type": "object",
65330
+ "properties": {
65331
+ "error_code": {
65332
+ "type": "string",
65333
+ "enum": [
65334
+ "not_logged_in"
65335
+ ]
65336
+ }
65337
+ }
65338
+ }
65339
+ ]
65340
+ }
65341
+ }
65342
+ }
65343
+ },
65344
+ "404": {
65345
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
65346
+ "content": {
65347
+ "application/json": {
65348
+ "schema": {
65349
+ "allOf": [
65350
+ {
65351
+ "$ref": "#/components/schemas/ErrorResponse"
65352
+ },
65353
+ {
65354
+ "type": "object",
65355
+ "properties": {
65356
+ "error_code": {
65357
+ "type": "string",
65358
+ "enum": [
65359
+ "account_not_found"
65360
+ ]
65361
+ }
65362
+ }
65363
+ }
65364
+ ]
65365
+ }
65366
+ }
65367
+ }
65368
+ },
65369
+ "429": {
65370
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
65371
+ "content": {
65372
+ "application/json": {
65373
+ "schema": {
65374
+ "allOf": [
65375
+ {
65376
+ "$ref": "#/components/schemas/ErrorResponse"
65377
+ },
65378
+ {
65379
+ "type": "object",
65380
+ "properties": {
65381
+ "error_code": {
65382
+ "type": "string",
65383
+ "enum": [
65384
+ "too_many_requests"
65385
+ ]
65386
+ }
65387
+ }
65388
+ }
65389
+ ]
65390
+ }
65391
+ }
65392
+ }
65393
+ },
65394
+ "500": {
65395
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
65396
+ "content": {
65397
+ "application/json": {
65398
+ "schema": {
65399
+ "allOf": [
65400
+ {
65401
+ "$ref": "#/components/schemas/ErrorResponse"
65402
+ },
65403
+ {
65404
+ "type": "object",
65405
+ "properties": {
65406
+ "error_code": {
65407
+ "type": "string",
65408
+ "enum": [
65409
+ "internal_error"
65410
+ ]
65411
+ }
65412
+ }
65413
+ }
65414
+ ]
65415
+ }
65416
+ }
65417
+ }
65418
+ }
65419
+ }
65420
+ }
65421
+ },
65422
+ "/me/grants/{grant_id}": {
65423
+ "delete": {
65424
+ "summary": "Disconnect an app",
65425
+ "tags": [
65426
+ "account"
65427
+ ],
65428
+ "description": "Revokes one of the session user’s grants. The app loses access at its next token refresh (within an hour), and has to ask again to reconnect.",
65429
+ "parameters": [
65430
+ {
65431
+ "schema": {
65432
+ "type": "string"
65433
+ },
65434
+ "in": "path",
65435
+ "name": "grant_id",
65436
+ "required": true
65437
+ }
65438
+ ],
65439
+ "responses": {
65440
+ "200": {
65441
+ "description": "Default Response"
65442
+ },
65443
+ "400": {
65444
+ "description": "`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
65445
+ "content": {
65446
+ "application/json": {
65447
+ "schema": {
65448
+ "allOf": [
65449
+ {
65450
+ "$ref": "#/components/schemas/ErrorResponse"
65451
+ },
65452
+ {
65453
+ "type": "object",
65454
+ "properties": {
65455
+ "error_code": {
65456
+ "type": "string",
65457
+ "enum": [
65458
+ "validation_error"
65459
+ ]
65460
+ }
65461
+ }
65462
+ }
65463
+ ]
65464
+ }
65465
+ }
65466
+ }
65467
+ },
65468
+ "401": {
65469
+ "description": "`not_logged_in` — There is no signed-in session for this request.",
65470
+ "content": {
65471
+ "application/json": {
65472
+ "schema": {
65473
+ "allOf": [
65474
+ {
65475
+ "$ref": "#/components/schemas/ErrorResponse"
65476
+ },
65477
+ {
65478
+ "type": "object",
65479
+ "properties": {
65480
+ "error_code": {
65481
+ "type": "string",
65482
+ "enum": [
65483
+ "not_logged_in"
65484
+ ]
65485
+ }
65486
+ }
65487
+ }
65488
+ ]
65489
+ }
65490
+ }
65491
+ }
65492
+ },
65493
+ "404": {
65494
+ "description": "`not_found` — The resource does not exist in this account.\n\n`account_not_found` — No Auth Account matches the request (domain, header or token).",
65495
+ "content": {
65496
+ "application/json": {
65497
+ "schema": {
65498
+ "allOf": [
65499
+ {
65500
+ "$ref": "#/components/schemas/ErrorResponse"
65501
+ },
65502
+ {
65503
+ "type": "object",
65504
+ "properties": {
65505
+ "error_code": {
65506
+ "type": "string",
65507
+ "enum": [
65508
+ "not_found",
65509
+ "account_not_found"
65510
+ ]
65511
+ }
65512
+ }
65513
+ }
65514
+ ]
65515
+ }
65516
+ }
65517
+ }
65518
+ },
65519
+ "429": {
65520
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
65521
+ "content": {
65522
+ "application/json": {
65523
+ "schema": {
65524
+ "allOf": [
65525
+ {
65526
+ "$ref": "#/components/schemas/ErrorResponse"
65527
+ },
65528
+ {
65529
+ "type": "object",
65530
+ "properties": {
65531
+ "error_code": {
65532
+ "type": "string",
65533
+ "enum": [
65534
+ "too_many_requests"
65535
+ ]
65536
+ }
65537
+ }
65538
+ }
65539
+ ]
65540
+ }
65541
+ }
65542
+ }
65543
+ },
65544
+ "500": {
65545
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
65546
+ "content": {
65547
+ "application/json": {
65548
+ "schema": {
65549
+ "allOf": [
65550
+ {
65551
+ "$ref": "#/components/schemas/ErrorResponse"
65552
+ },
65553
+ {
65554
+ "type": "object",
65555
+ "properties": {
65556
+ "error_code": {
65557
+ "type": "string",
65558
+ "enum": [
65559
+ "internal_error"
65560
+ ]
65561
+ }
65562
+ }
65563
+ }
65564
+ ]
65565
+ }
65566
+ }
65567
+ }
65568
+ }
65569
+ }
65570
+ }
65571
+ },
64420
65572
  "/me": {
64421
65573
  "get": {
64422
65574
  "operationId": "session/me",
@@ -67432,6 +68584,9 @@
67432
68584
  },
67433
68585
  "scope": {
67434
68586
  "type": "string"
68587
+ },
68588
+ "issued_token_type": {
68589
+ "type": "string"
67435
68590
  }
67436
68591
  }
67437
68592
  }
@@ -67927,6 +69082,9 @@
67927
69082
  },
67928
69083
  "scope": {
67929
69084
  "type": "string"
69085
+ },
69086
+ "issued_token_type": {
69087
+ "type": "string"
67930
69088
  }
67931
69089
  }
67932
69090
  }
@@ -69292,6 +70450,71 @@
69292
70450
  }
69293
70451
  }
69294
70452
  },
70453
+ "/.well-known/oauth-authorization-server": {
70454
+ "get": {
70455
+ "operationId": "oauth/authorizationServerMetadata",
70456
+ "summary": "OAuth 2.0 Authorization Server Metadata (RFC 8414)",
70457
+ "tags": [
70458
+ "oauth"
70459
+ ],
70460
+ "description": "The same provider metadata as the OpenID Connect Discovery document, at the RFC 8414 location that OAuth 2.0 and MCP clients query.",
70461
+ "responses": {
70462
+ "200": {
70463
+ "description": "Default Response"
70464
+ },
70465
+ "429": {
70466
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
70467
+ "content": {
70468
+ "application/json": {
70469
+ "schema": {
70470
+ "allOf": [
70471
+ {
70472
+ "$ref": "#/components/schemas/ErrorResponse"
70473
+ },
70474
+ {
70475
+ "type": "object",
70476
+ "properties": {
70477
+ "error_code": {
70478
+ "type": "string",
70479
+ "enum": [
70480
+ "too_many_requests"
70481
+ ]
70482
+ }
70483
+ }
70484
+ }
70485
+ ]
70486
+ }
70487
+ }
70488
+ }
70489
+ },
70490
+ "500": {
70491
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
70492
+ "content": {
70493
+ "application/json": {
70494
+ "schema": {
70495
+ "allOf": [
70496
+ {
70497
+ "$ref": "#/components/schemas/ErrorResponse"
70498
+ },
70499
+ {
70500
+ "type": "object",
70501
+ "properties": {
70502
+ "error_code": {
70503
+ "type": "string",
70504
+ "enum": [
70505
+ "internal_error"
70506
+ ]
70507
+ }
70508
+ }
70509
+ }
70510
+ ]
70511
+ }
70512
+ }
70513
+ }
70514
+ }
70515
+ }
70516
+ }
70517
+ },
69295
70518
  "/.well-known/jwks.json": {
69296
70519
  "get": {
69297
70520
  "operationId": "oauth/jwks",
@@ -69790,7 +71013,6 @@
69790
71013
  "type": "object",
69791
71014
  "required": [
69792
71015
  "client_id",
69793
- "client_secret",
69794
71016
  "client_id_issued_at",
69795
71017
  "client_secret_expires_at",
69796
71018
  "redirect_uris",
@@ -70027,6 +71249,669 @@
70027
71249
  }
70028
71250
  }
70029
71251
  },
71252
+ "/consent/context": {
71253
+ "get": {
71254
+ "summary": "What the consent screen shows",
71255
+ "tags": [
71256
+ "oauth"
71257
+ ],
71258
+ "description": "For a login parked on the consent screen: the client asking (name, logo, where it redirects), the user, the API and permissions requested, and — when the API offers one — the choice the user has to make (e.g. which project).",
71259
+ "parameters": [
71260
+ {
71261
+ "schema": {
71262
+ "type": "string"
71263
+ },
71264
+ "in": "query",
71265
+ "name": "state",
71266
+ "required": true
71267
+ }
71268
+ ],
71269
+ "responses": {
71270
+ "200": {
71271
+ "description": "Default Response",
71272
+ "content": {
71273
+ "application/json": {
71274
+ "schema": {
71275
+ "type": "object",
71276
+ "required": [
71277
+ "account",
71278
+ "client",
71279
+ "user",
71280
+ "scopes"
71281
+ ],
71282
+ "properties": {
71283
+ "account": {
71284
+ "type": "object",
71285
+ "properties": {
71286
+ "name": {
71287
+ "type": "string"
71288
+ }
71289
+ }
71290
+ },
71291
+ "client": {
71292
+ "type": "object",
71293
+ "required": [
71294
+ "name",
71295
+ "localhost_only"
71296
+ ],
71297
+ "properties": {
71298
+ "name": {
71299
+ "type": "string"
71300
+ },
71301
+ "logo_uri": {
71302
+ "type": "string"
71303
+ },
71304
+ "client_uri": {
71305
+ "type": "string"
71306
+ },
71307
+ "redirect_host": {
71308
+ "type": "string"
71309
+ },
71310
+ "localhost_only": {
71311
+ "type": "boolean"
71312
+ },
71313
+ "metadata_document_url": {
71314
+ "type": "string"
71315
+ }
71316
+ }
71317
+ },
71318
+ "user": {
71319
+ "type": "object",
71320
+ "properties": {
71321
+ "email": {
71322
+ "type": "string"
71323
+ },
71324
+ "name": {
71325
+ "type": "string"
71326
+ }
71327
+ }
71328
+ },
71329
+ "resource": {
71330
+ "type": "object",
71331
+ "required": [
71332
+ "identifier",
71333
+ "name"
71334
+ ],
71335
+ "properties": {
71336
+ "identifier": {
71337
+ "type": "string"
71338
+ },
71339
+ "name": {
71340
+ "type": "string"
71341
+ }
71342
+ }
71343
+ },
71344
+ "scopes": {
71345
+ "type": "array",
71346
+ "items": {
71347
+ "type": "object",
71348
+ "required": [
71349
+ "value",
71350
+ "description"
71351
+ ],
71352
+ "properties": {
71353
+ "value": {
71354
+ "type": "string"
71355
+ },
71356
+ "description": {
71357
+ "type": "string"
71358
+ }
71359
+ }
71360
+ }
71361
+ },
71362
+ "choice": {
71363
+ "type": "object",
71364
+ "required": [
71365
+ "label",
71366
+ "options"
71367
+ ],
71368
+ "properties": {
71369
+ "label": {
71370
+ "type": "string"
71371
+ },
71372
+ "options": {
71373
+ "type": "array",
71374
+ "items": {
71375
+ "type": "object",
71376
+ "required": [
71377
+ "id",
71378
+ "name"
71379
+ ],
71380
+ "properties": {
71381
+ "id": {
71382
+ "type": "string"
71383
+ },
71384
+ "name": {
71385
+ "type": "string"
71386
+ }
71387
+ }
71388
+ }
71389
+ }
71390
+ }
71391
+ }
71392
+ }
71393
+ }
71394
+ }
71395
+ }
71396
+ },
71397
+ "400": {
71398
+ "description": "`invalid_state` — The `state` is missing, expired, or does not describe a resumable step.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
71399
+ "content": {
71400
+ "application/json": {
71401
+ "schema": {
71402
+ "allOf": [
71403
+ {
71404
+ "$ref": "#/components/schemas/ErrorResponse"
71405
+ },
71406
+ {
71407
+ "type": "object",
71408
+ "properties": {
71409
+ "error_code": {
71410
+ "type": "string",
71411
+ "enum": [
71412
+ "invalid_state",
71413
+ "validation_error"
71414
+ ]
71415
+ }
71416
+ }
71417
+ }
71418
+ ]
71419
+ }
71420
+ }
71421
+ }
71422
+ },
71423
+ "401": {
71424
+ "description": "`state_mismatch` — The `state` belongs to another account, session, client or ceremony.\n\n`session_missing` — The session that started this login no longer exists.",
71425
+ "content": {
71426
+ "application/json": {
71427
+ "schema": {
71428
+ "allOf": [
71429
+ {
71430
+ "$ref": "#/components/schemas/ErrorResponse"
71431
+ },
71432
+ {
71433
+ "type": "object",
71434
+ "properties": {
71435
+ "error_code": {
71436
+ "type": "string",
71437
+ "enum": [
71438
+ "state_mismatch",
71439
+ "session_missing"
71440
+ ]
71441
+ }
71442
+ }
71443
+ }
71444
+ ]
71445
+ }
71446
+ }
71447
+ }
71448
+ },
71449
+ "404": {
71450
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
71451
+ "content": {
71452
+ "application/json": {
71453
+ "schema": {
71454
+ "allOf": [
71455
+ {
71456
+ "$ref": "#/components/schemas/ErrorResponse"
71457
+ },
71458
+ {
71459
+ "type": "object",
71460
+ "properties": {
71461
+ "error_code": {
71462
+ "type": "string",
71463
+ "enum": [
71464
+ "account_not_found"
71465
+ ]
71466
+ }
71467
+ }
71468
+ }
71469
+ ]
71470
+ }
71471
+ }
71472
+ }
71473
+ },
71474
+ "429": {
71475
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
71476
+ "content": {
71477
+ "application/json": {
71478
+ "schema": {
71479
+ "allOf": [
71480
+ {
71481
+ "$ref": "#/components/schemas/ErrorResponse"
71482
+ },
71483
+ {
71484
+ "type": "object",
71485
+ "properties": {
71486
+ "error_code": {
71487
+ "type": "string",
71488
+ "enum": [
71489
+ "too_many_requests"
71490
+ ]
71491
+ }
71492
+ }
71493
+ }
71494
+ ]
71495
+ }
71496
+ }
71497
+ }
71498
+ },
71499
+ "500": {
71500
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
71501
+ "content": {
71502
+ "application/json": {
71503
+ "schema": {
71504
+ "allOf": [
71505
+ {
71506
+ "$ref": "#/components/schemas/ErrorResponse"
71507
+ },
71508
+ {
71509
+ "type": "object",
71510
+ "properties": {
71511
+ "error_code": {
71512
+ "type": "string",
71513
+ "enum": [
71514
+ "internal_error"
71515
+ ]
71516
+ }
71517
+ }
71518
+ }
71519
+ ]
71520
+ }
71521
+ }
71522
+ }
71523
+ },
71524
+ "502": {
71525
+ "description": "`consent_options_unavailable` — The consent screen could not load the choices from the API being authorized (its `consent_options.url`). Try again in a moment.",
71526
+ "content": {
71527
+ "application/json": {
71528
+ "schema": {
71529
+ "allOf": [
71530
+ {
71531
+ "$ref": "#/components/schemas/ErrorResponse"
71532
+ },
71533
+ {
71534
+ "type": "object",
71535
+ "properties": {
71536
+ "error_code": {
71537
+ "type": "string",
71538
+ "enum": [
71539
+ "consent_options_unavailable"
71540
+ ]
71541
+ }
71542
+ }
71543
+ }
71544
+ ]
71545
+ }
71546
+ }
71547
+ }
71548
+ }
71549
+ }
71550
+ }
71551
+ },
71552
+ "/consent": {
71553
+ "post": {
71554
+ "summary": "Allow or deny a client on the consent screen",
71555
+ "tags": [
71556
+ "oauth"
71557
+ ],
71558
+ "description": "Records the decision and returns where the browser goes next: on `allow`, on to the client with its code (the grant is remembered, so the screen is not shown again for the same permissions); on `deny`, back to the client with `error=access_denied`. `choice` is required when the consent context offered one, and must be one of its options.",
71559
+ "requestBody": {
71560
+ "required": true,
71561
+ "content": {
71562
+ "application/json": {
71563
+ "schema": {
71564
+ "type": "object",
71565
+ "required": [
71566
+ "state",
71567
+ "decision"
71568
+ ],
71569
+ "properties": {
71570
+ "state": {
71571
+ "type": "string"
71572
+ },
71573
+ "decision": {
71574
+ "anyOf": [
71575
+ {
71576
+ "type": "string",
71577
+ "enum": [
71578
+ "allow"
71579
+ ]
71580
+ },
71581
+ {
71582
+ "type": "string",
71583
+ "enum": [
71584
+ "deny"
71585
+ ]
71586
+ }
71587
+ ]
71588
+ },
71589
+ "choice": {
71590
+ "type": "string"
71591
+ }
71592
+ }
71593
+ }
71594
+ }
71595
+ }
71596
+ },
71597
+ "responses": {
71598
+ "200": {
71599
+ "description": "Default Response",
71600
+ "content": {
71601
+ "application/json": {
71602
+ "schema": {
71603
+ "type": "object",
71604
+ "required": [
71605
+ "redirect_url"
71606
+ ],
71607
+ "properties": {
71608
+ "redirect_url": {
71609
+ "type": "string"
71610
+ }
71611
+ }
71612
+ }
71613
+ }
71614
+ }
71615
+ },
71616
+ "400": {
71617
+ "description": "`invalid_state` — The `state` is missing, expired, or does not describe a resumable step.\n\n`consent_choice_invalid` — The choice sent with the consent decision is not one the API offered for this user.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
71618
+ "content": {
71619
+ "application/json": {
71620
+ "schema": {
71621
+ "allOf": [
71622
+ {
71623
+ "$ref": "#/components/schemas/ErrorResponse"
71624
+ },
71625
+ {
71626
+ "type": "object",
71627
+ "properties": {
71628
+ "error_code": {
71629
+ "type": "string",
71630
+ "enum": [
71631
+ "invalid_state",
71632
+ "consent_choice_invalid",
71633
+ "validation_error"
71634
+ ]
71635
+ }
71636
+ }
71637
+ }
71638
+ ]
71639
+ }
71640
+ }
71641
+ }
71642
+ },
71643
+ "401": {
71644
+ "description": "`state_mismatch` — The `state` belongs to another account, session, client or ceremony.\n\n`session_missing` — The session that started this login no longer exists.",
71645
+ "content": {
71646
+ "application/json": {
71647
+ "schema": {
71648
+ "allOf": [
71649
+ {
71650
+ "$ref": "#/components/schemas/ErrorResponse"
71651
+ },
71652
+ {
71653
+ "type": "object",
71654
+ "properties": {
71655
+ "error_code": {
71656
+ "type": "string",
71657
+ "enum": [
71658
+ "state_mismatch",
71659
+ "session_missing"
71660
+ ]
71661
+ }
71662
+ }
71663
+ }
71664
+ ]
71665
+ }
71666
+ }
71667
+ }
71668
+ },
71669
+ "404": {
71670
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
71671
+ "content": {
71672
+ "application/json": {
71673
+ "schema": {
71674
+ "allOf": [
71675
+ {
71676
+ "$ref": "#/components/schemas/ErrorResponse"
71677
+ },
71678
+ {
71679
+ "type": "object",
71680
+ "properties": {
71681
+ "error_code": {
71682
+ "type": "string",
71683
+ "enum": [
71684
+ "account_not_found"
71685
+ ]
71686
+ }
71687
+ }
71688
+ }
71689
+ ]
71690
+ }
71691
+ }
71692
+ }
71693
+ },
71694
+ "429": {
71695
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
71696
+ "content": {
71697
+ "application/json": {
71698
+ "schema": {
71699
+ "allOf": [
71700
+ {
71701
+ "$ref": "#/components/schemas/ErrorResponse"
71702
+ },
71703
+ {
71704
+ "type": "object",
71705
+ "properties": {
71706
+ "error_code": {
71707
+ "type": "string",
71708
+ "enum": [
71709
+ "too_many_requests"
71710
+ ]
71711
+ }
71712
+ }
71713
+ }
71714
+ ]
71715
+ }
71716
+ }
71717
+ }
71718
+ },
71719
+ "500": {
71720
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
71721
+ "content": {
71722
+ "application/json": {
71723
+ "schema": {
71724
+ "allOf": [
71725
+ {
71726
+ "$ref": "#/components/schemas/ErrorResponse"
71727
+ },
71728
+ {
71729
+ "type": "object",
71730
+ "properties": {
71731
+ "error_code": {
71732
+ "type": "string",
71733
+ "enum": [
71734
+ "internal_error"
71735
+ ]
71736
+ }
71737
+ }
71738
+ }
71739
+ ]
71740
+ }
71741
+ }
71742
+ }
71743
+ },
71744
+ "502": {
71745
+ "description": "`consent_options_unavailable` — The consent screen could not load the choices from the API being authorized (its `consent_options.url`). Try again in a moment.",
71746
+ "content": {
71747
+ "application/json": {
71748
+ "schema": {
71749
+ "allOf": [
71750
+ {
71751
+ "$ref": "#/components/schemas/ErrorResponse"
71752
+ },
71753
+ {
71754
+ "type": "object",
71755
+ "properties": {
71756
+ "error_code": {
71757
+ "type": "string",
71758
+ "enum": [
71759
+ "consent_options_unavailable"
71760
+ ]
71761
+ }
71762
+ }
71763
+ }
71764
+ ]
71765
+ }
71766
+ }
71767
+ }
71768
+ }
71769
+ }
71770
+ }
71771
+ },
71772
+ "/oauth/revoke": {
71773
+ "post": {
71774
+ "operationId": "oauth/revoke",
71775
+ "summary": "Revoke a token (RFC 7009)",
71776
+ "tags": [
71777
+ "oauth"
71778
+ ],
71779
+ "description": "Revokes a refresh token (and, for a client the End-User had to allow, the grant behind it). Access tokens are short-lived and not revocable; the response is 200 either way, also for an unknown token. The client authenticates as at the token endpoint: `client_secret_basic`, `client_secret_post`, or just `client_id` for a public client.",
71780
+ "requestBody": {
71781
+ "required": true,
71782
+ "content": {
71783
+ "application/json": {
71784
+ "schema": {
71785
+ "type": "object",
71786
+ "required": [
71787
+ "token"
71788
+ ],
71789
+ "properties": {
71790
+ "token": {
71791
+ "type": "string"
71792
+ },
71793
+ "token_type_hint": {
71794
+ "type": "string"
71795
+ },
71796
+ "client_id": {
71797
+ "type": "string"
71798
+ },
71799
+ "client_secret": {
71800
+ "type": "string"
71801
+ }
71802
+ }
71803
+ }
71804
+ }
71805
+ }
71806
+ },
71807
+ "responses": {
71808
+ "200": {
71809
+ "description": "Default Response"
71810
+ },
71811
+ "400": {
71812
+ "description": "`invalid_client` — The `client_id` in the request does not name a client of this account.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
71813
+ "content": {
71814
+ "application/json": {
71815
+ "schema": {
71816
+ "allOf": [
71817
+ {
71818
+ "$ref": "#/components/schemas/ErrorResponse"
71819
+ },
71820
+ {
71821
+ "type": "object",
71822
+ "properties": {
71823
+ "error_code": {
71824
+ "type": "string",
71825
+ "enum": [
71826
+ "invalid_client",
71827
+ "validation_error"
71828
+ ]
71829
+ }
71830
+ }
71831
+ }
71832
+ ]
71833
+ }
71834
+ }
71835
+ }
71836
+ },
71837
+ "404": {
71838
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
71839
+ "content": {
71840
+ "application/json": {
71841
+ "schema": {
71842
+ "allOf": [
71843
+ {
71844
+ "$ref": "#/components/schemas/ErrorResponse"
71845
+ },
71846
+ {
71847
+ "type": "object",
71848
+ "properties": {
71849
+ "error_code": {
71850
+ "type": "string",
71851
+ "enum": [
71852
+ "account_not_found"
71853
+ ]
71854
+ }
71855
+ }
71856
+ }
71857
+ ]
71858
+ }
71859
+ }
71860
+ }
71861
+ },
71862
+ "429": {
71863
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
71864
+ "content": {
71865
+ "application/json": {
71866
+ "schema": {
71867
+ "allOf": [
71868
+ {
71869
+ "$ref": "#/components/schemas/ErrorResponse"
71870
+ },
71871
+ {
71872
+ "type": "object",
71873
+ "properties": {
71874
+ "error_code": {
71875
+ "type": "string",
71876
+ "enum": [
71877
+ "too_many_requests"
71878
+ ]
71879
+ }
71880
+ }
71881
+ }
71882
+ ]
71883
+ }
71884
+ }
71885
+ }
71886
+ },
71887
+ "500": {
71888
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
71889
+ "content": {
71890
+ "application/json": {
71891
+ "schema": {
71892
+ "allOf": [
71893
+ {
71894
+ "$ref": "#/components/schemas/ErrorResponse"
71895
+ },
71896
+ {
71897
+ "type": "object",
71898
+ "properties": {
71899
+ "error_code": {
71900
+ "type": "string",
71901
+ "enum": [
71902
+ "internal_error"
71903
+ ]
71904
+ }
71905
+ }
71906
+ }
71907
+ ]
71908
+ }
71909
+ }
71910
+ }
71911
+ }
71912
+ }
71913
+ }
71914
+ },
70030
71915
  "/usernamepassword/login": {
70031
71916
  "post": {
70032
71917
  "operationId": "usernamepassword/login",