@faable/auth-sdk 2.7.83 → 2.7.85

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.66.0",
6
+ "version": "2.68.0",
7
7
  "license": {
8
8
  "name": "private",
9
9
  "url": "https://faable.com/docs/platform/privacy-policy"
@@ -677,6 +677,11 @@
677
677
  "enabled": {
678
678
  "type": "boolean"
679
679
  },
680
+ "organization": {
681
+ "type": "string",
682
+ "description": "The Organization whose identity provider this is (`organization_…`), or `null`. Only `oidc` connections. Reached by home realm discovery from the organization's verified email domains, and only accepts emails of those domains. Pro plan.",
683
+ "nullable": true
684
+ },
680
685
  "enabled_clients": {
681
686
  "type": "array",
682
687
  "items": {
@@ -881,6 +886,16 @@
881
886
  "jwks_url": {
882
887
  "type": "string"
883
888
  },
889
+ "token_url": {
890
+ "type": "string"
891
+ },
892
+ "userinfo_url": {
893
+ "type": "string"
894
+ },
895
+ "organization": {
896
+ "type": "string",
897
+ "description": "The Organization whose identity provider this is (`organization_…`), or `null`. Only `oidc` connections. Reached by home realm discovery from the organization's verified email domains, and only accepts emails of those domains. Pro plan."
898
+ },
884
899
  "scope": {
885
900
  "type": "array",
886
901
  "items": {
@@ -1193,6 +1208,10 @@
1193
1208
  }
1194
1209
  ],
1195
1210
  "description": "What users of this database connection sign in with: `email`, `username`, or `email_or_username` (email first, then username). The login looks up only the matching field, and the hosted login screen asks for it — validating the address format under `email`. New database connections default to `email`; a connection created before this setting existed behaves as `email_or_username`. Only meaningful on `database` connections."
1211
+ },
1212
+ "organization": {
1213
+ "type": "string",
1214
+ "nullable": true
1196
1215
  }
1197
1216
  },
1198
1217
  "description": "Partial update for a Connection. Only the supplied fields are modified. `connection_type` is intentionally excluded — changing it would orphan every identity already linked to this connection.",
@@ -3674,6 +3693,8 @@
3674
3693
  "description",
3675
3694
  "logo_url",
3676
3695
  "domains",
3696
+ "require_sso",
3697
+ "auto_join",
3677
3698
  "admins",
3678
3699
  "account",
3679
3700
  "createdAt"
@@ -3731,6 +3752,34 @@
3731
3752
  },
3732
3753
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
3733
3754
  },
3755
+ "require_sso": {
3756
+ "type": "boolean",
3757
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
3758
+ },
3759
+ "auto_join": {
3760
+ "type": "array",
3761
+ "items": {
3762
+ "type": "object",
3763
+ "required": [
3764
+ "team",
3765
+ "roles"
3766
+ ],
3767
+ "properties": {
3768
+ "team": {
3769
+ "type": "string",
3770
+ "description": "A team of this organization."
3771
+ },
3772
+ "roles": {
3773
+ "type": "array",
3774
+ "items": {
3775
+ "type": "string"
3776
+ },
3777
+ "description": "Role ids the member gets in that team."
3778
+ }
3779
+ }
3780
+ },
3781
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
3782
+ },
3734
3783
  "admins": {
3735
3784
  "type": "array",
3736
3785
  "items": {
@@ -7809,7 +7858,7 @@
7809
7858
  },
7810
7859
  "ErrorCode": {
7811
7860
  "type": "string",
7812
- "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_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.",
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.",
7813
7862
  "enum": [
7814
7863
  "bad_request",
7815
7864
  "validation_error",
@@ -7936,6 +7985,9 @@
7936
7985
  "organization_domain_taken",
7937
7986
  "organization_domain_unverified",
7938
7987
  "plan_unavailable",
7988
+ "organization_domain_mismatch",
7989
+ "team_not_in_organization",
7990
+ "organization_has_no_idp",
7939
7991
  "organization_not_found",
7940
7992
  "invalid_user",
7941
7993
  "not_an_organization_admin",
@@ -14956,6 +15008,16 @@
14956
15008
  "jwks_url": {
14957
15009
  "type": "string"
14958
15010
  },
15011
+ "token_url": {
15012
+ "type": "string"
15013
+ },
15014
+ "userinfo_url": {
15015
+ "type": "string"
15016
+ },
15017
+ "organization": {
15018
+ "type": "string",
15019
+ "description": "The Organization whose identity provider this is (`organization_…`), or `null`. Only `oidc` connections. Reached by home realm discovery from the organization's verified email domains, and only accepts emails of those domains. Pro plan."
15020
+ },
14959
15021
  "scope": {
14960
15022
  "type": "array",
14961
15023
  "items": {
@@ -15183,6 +15245,11 @@
15183
15245
  "enabled": {
15184
15246
  "type": "boolean"
15185
15247
  },
15248
+ "organization": {
15249
+ "type": "string",
15250
+ "description": "The Organization whose identity provider this is (`organization_…`), or `null`. Only `oidc` connections. Reached by home realm discovery from the organization's verified email domains, and only accepts emails of those domains. Pro plan.",
15251
+ "nullable": true
15252
+ },
15186
15253
  "enabled_clients": {
15187
15254
  "type": "array",
15188
15255
  "items": {
@@ -15607,6 +15674,11 @@
15607
15674
  "enabled": {
15608
15675
  "type": "boolean"
15609
15676
  },
15677
+ "organization": {
15678
+ "type": "string",
15679
+ "description": "The Organization whose identity provider this is (`organization_…`), or `null`. Only `oidc` connections. Reached by home realm discovery from the organization's verified email domains, and only accepts emails of those domains. Pro plan.",
15680
+ "nullable": true
15681
+ },
15610
15682
  "enabled_clients": {
15611
15683
  "type": "array",
15612
15684
  "items": {
@@ -16108,6 +16180,10 @@
16108
16180
  }
16109
16181
  ],
16110
16182
  "description": "What users of this database connection sign in with: `email`, `username`, or `email_or_username` (email first, then username). The login looks up only the matching field, and the hosted login screen asks for it — validating the address format under `email`. New database connections default to `email`; a connection created before this setting existed behaves as `email_or_username`. Only meaningful on `database` connections."
16183
+ },
16184
+ "organization": {
16185
+ "type": "string",
16186
+ "nullable": true
16111
16187
  }
16112
16188
  },
16113
16189
  "description": "Partial update for a Connection. Only the supplied fields are modified. `connection_type` is intentionally excluded — changing it would orphan every identity already linked to this connection.",
@@ -16214,6 +16290,11 @@
16214
16290
  "enabled": {
16215
16291
  "type": "boolean"
16216
16292
  },
16293
+ "organization": {
16294
+ "type": "string",
16295
+ "description": "The Organization whose identity provider this is (`organization_…`), or `null`. Only `oidc` connections. Reached by home realm discovery from the organization's verified email domains, and only accepts emails of those domains. Pro plan.",
16296
+ "nullable": true
16297
+ },
16217
16298
  "enabled_clients": {
16218
16299
  "type": "array",
16219
16300
  "items": {
@@ -16638,6 +16719,11 @@
16638
16719
  "enabled": {
16639
16720
  "type": "boolean"
16640
16721
  },
16722
+ "organization": {
16723
+ "type": "string",
16724
+ "description": "The Organization whose identity provider this is (`organization_…`), or `null`. Only `oidc` connections. Reached by home realm discovery from the organization's verified email domains, and only accepts emails of those domains. Pro plan.",
16725
+ "nullable": true
16726
+ },
16641
16727
  "enabled_clients": {
16642
16728
  "type": "array",
16643
16729
  "items": {
@@ -17374,6 +17460,45 @@
17374
17460
  "properties": {
17375
17461
  "ok": {
17376
17462
  "type": "boolean"
17463
+ },
17464
+ "home_realm": {
17465
+ "type": "object",
17466
+ "required": [
17467
+ "connection_id",
17468
+ "organization"
17469
+ ],
17470
+ "properties": {
17471
+ "connection_id": {
17472
+ "type": "string"
17473
+ },
17474
+ "organization": {
17475
+ "type": "object",
17476
+ "required": [
17477
+ "id",
17478
+ "name",
17479
+ "logo_url"
17480
+ ],
17481
+ "properties": {
17482
+ "id": {
17483
+ "type": "string"
17484
+ },
17485
+ "name": {
17486
+ "type": "string"
17487
+ },
17488
+ "logo_url": {
17489
+ "anyOf": [
17490
+ {
17491
+ "type": "string"
17492
+ },
17493
+ {
17494
+ "type": "null"
17495
+ }
17496
+ ]
17497
+ }
17498
+ }
17499
+ }
17500
+ },
17501
+ "description": "The identifier is an email of an organization's verified domain, and that organization has its own identity provider: continue with `/authorize?resume_state=<state>&connection=<connection_id>` instead of the method chooser (arch/auth/sso.md F3)."
17377
17502
  }
17378
17503
  }
17379
17504
  }
@@ -35811,6 +35936,8 @@
35811
35936
  "description",
35812
35937
  "logo_url",
35813
35938
  "domains",
35939
+ "require_sso",
35940
+ "auto_join",
35814
35941
  "admins",
35815
35942
  "account",
35816
35943
  "createdAt"
@@ -35868,6 +35995,34 @@
35868
35995
  },
35869
35996
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
35870
35997
  },
35998
+ "require_sso": {
35999
+ "type": "boolean",
36000
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
36001
+ },
36002
+ "auto_join": {
36003
+ "type": "array",
36004
+ "items": {
36005
+ "type": "object",
36006
+ "required": [
36007
+ "team",
36008
+ "roles"
36009
+ ],
36010
+ "properties": {
36011
+ "team": {
36012
+ "type": "string",
36013
+ "description": "A team of this organization."
36014
+ },
36015
+ "roles": {
36016
+ "type": "array",
36017
+ "items": {
36018
+ "type": "string"
36019
+ },
36020
+ "description": "Role ids the member gets in that team."
36021
+ }
36022
+ }
36023
+ },
36024
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
36025
+ },
35871
36026
  "admins": {
35872
36027
  "type": "array",
35873
36028
  "items": {
@@ -36093,6 +36248,8 @@
36093
36248
  "description",
36094
36249
  "logo_url",
36095
36250
  "domains",
36251
+ "require_sso",
36252
+ "auto_join",
36096
36253
  "admins",
36097
36254
  "account",
36098
36255
  "createdAt"
@@ -36150,6 +36307,34 @@
36150
36307
  },
36151
36308
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
36152
36309
  },
36310
+ "require_sso": {
36311
+ "type": "boolean",
36312
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
36313
+ },
36314
+ "auto_join": {
36315
+ "type": "array",
36316
+ "items": {
36317
+ "type": "object",
36318
+ "required": [
36319
+ "team",
36320
+ "roles"
36321
+ ],
36322
+ "properties": {
36323
+ "team": {
36324
+ "type": "string",
36325
+ "description": "A team of this organization."
36326
+ },
36327
+ "roles": {
36328
+ "type": "array",
36329
+ "items": {
36330
+ "type": "string"
36331
+ },
36332
+ "description": "Role ids the member gets in that team."
36333
+ }
36334
+ }
36335
+ },
36336
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
36337
+ },
36153
36338
  "admins": {
36154
36339
  "type": "array",
36155
36340
  "items": {
@@ -36410,6 +36595,8 @@
36410
36595
  "description",
36411
36596
  "logo_url",
36412
36597
  "domains",
36598
+ "require_sso",
36599
+ "auto_join",
36413
36600
  "admins",
36414
36601
  "account",
36415
36602
  "createdAt"
@@ -36467,6 +36654,34 @@
36467
36654
  },
36468
36655
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
36469
36656
  },
36657
+ "require_sso": {
36658
+ "type": "boolean",
36659
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
36660
+ },
36661
+ "auto_join": {
36662
+ "type": "array",
36663
+ "items": {
36664
+ "type": "object",
36665
+ "required": [
36666
+ "team",
36667
+ "roles"
36668
+ ],
36669
+ "properties": {
36670
+ "team": {
36671
+ "type": "string",
36672
+ "description": "A team of this organization."
36673
+ },
36674
+ "roles": {
36675
+ "type": "array",
36676
+ "items": {
36677
+ "type": "string"
36678
+ },
36679
+ "description": "Role ids the member gets in that team."
36680
+ }
36681
+ }
36682
+ },
36683
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
36684
+ },
36470
36685
  "admins": {
36471
36686
  "type": "array",
36472
36687
  "items": {
@@ -36692,6 +36907,8 @@
36692
36907
  "description",
36693
36908
  "logo_url",
36694
36909
  "domains",
36910
+ "require_sso",
36911
+ "auto_join",
36695
36912
  "admins",
36696
36913
  "account",
36697
36914
  "createdAt"
@@ -36749,6 +36966,34 @@
36749
36966
  },
36750
36967
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
36751
36968
  },
36969
+ "require_sso": {
36970
+ "type": "boolean",
36971
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
36972
+ },
36973
+ "auto_join": {
36974
+ "type": "array",
36975
+ "items": {
36976
+ "type": "object",
36977
+ "required": [
36978
+ "team",
36979
+ "roles"
36980
+ ],
36981
+ "properties": {
36982
+ "team": {
36983
+ "type": "string",
36984
+ "description": "A team of this organization."
36985
+ },
36986
+ "roles": {
36987
+ "type": "array",
36988
+ "items": {
36989
+ "type": "string"
36990
+ },
36991
+ "description": "Role ids the member gets in that team."
36992
+ }
36993
+ }
36994
+ },
36995
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
36996
+ },
36752
36997
  "admins": {
36753
36998
  "type": "array",
36754
36999
  "items": {
@@ -36996,6 +37241,8 @@
36996
37241
  "description",
36997
37242
  "logo_url",
36998
37243
  "domains",
37244
+ "require_sso",
37245
+ "auto_join",
36999
37246
  "admins",
37000
37247
  "account",
37001
37248
  "createdAt"
@@ -37053,6 +37300,34 @@
37053
37300
  },
37054
37301
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
37055
37302
  },
37303
+ "require_sso": {
37304
+ "type": "boolean",
37305
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
37306
+ },
37307
+ "auto_join": {
37308
+ "type": "array",
37309
+ "items": {
37310
+ "type": "object",
37311
+ "required": [
37312
+ "team",
37313
+ "roles"
37314
+ ],
37315
+ "properties": {
37316
+ "team": {
37317
+ "type": "string",
37318
+ "description": "A team of this organization."
37319
+ },
37320
+ "roles": {
37321
+ "type": "array",
37322
+ "items": {
37323
+ "type": "string"
37324
+ },
37325
+ "description": "Role ids the member gets in that team."
37326
+ }
37327
+ }
37328
+ },
37329
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
37330
+ },
37056
37331
  "admins": {
37057
37332
  "type": "array",
37058
37333
  "items": {
@@ -37287,6 +37562,8 @@
37287
37562
  "description",
37288
37563
  "logo_url",
37289
37564
  "domains",
37565
+ "require_sso",
37566
+ "auto_join",
37290
37567
  "admins",
37291
37568
  "account",
37292
37569
  "createdAt"
@@ -37344,6 +37621,34 @@
37344
37621
  },
37345
37622
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
37346
37623
  },
37624
+ "require_sso": {
37625
+ "type": "boolean",
37626
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
37627
+ },
37628
+ "auto_join": {
37629
+ "type": "array",
37630
+ "items": {
37631
+ "type": "object",
37632
+ "required": [
37633
+ "team",
37634
+ "roles"
37635
+ ],
37636
+ "properties": {
37637
+ "team": {
37638
+ "type": "string",
37639
+ "description": "A team of this organization."
37640
+ },
37641
+ "roles": {
37642
+ "type": "array",
37643
+ "items": {
37644
+ "type": "string"
37645
+ },
37646
+ "description": "Role ids the member gets in that team."
37647
+ }
37648
+ }
37649
+ },
37650
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
37651
+ },
37347
37652
  "admins": {
37348
37653
  "type": "array",
37349
37654
  "items": {
@@ -37616,6 +37921,8 @@
37616
37921
  "description",
37617
37922
  "logo_url",
37618
37923
  "domains",
37924
+ "require_sso",
37925
+ "auto_join",
37619
37926
  "admins",
37620
37927
  "account",
37621
37928
  "createdAt"
@@ -37673,6 +37980,34 @@
37673
37980
  },
37674
37981
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
37675
37982
  },
37983
+ "require_sso": {
37984
+ "type": "boolean",
37985
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
37986
+ },
37987
+ "auto_join": {
37988
+ "type": "array",
37989
+ "items": {
37990
+ "type": "object",
37991
+ "required": [
37992
+ "team",
37993
+ "roles"
37994
+ ],
37995
+ "properties": {
37996
+ "team": {
37997
+ "type": "string",
37998
+ "description": "A team of this organization."
37999
+ },
38000
+ "roles": {
38001
+ "type": "array",
38002
+ "items": {
38003
+ "type": "string"
38004
+ },
38005
+ "description": "Role ids the member gets in that team."
38006
+ }
38007
+ }
38008
+ },
38009
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
38010
+ },
37676
38011
  "admins": {
37677
38012
  "type": "array",
37678
38013
  "items": {
@@ -37915,6 +38250,8 @@
37915
38250
  "description",
37916
38251
  "logo_url",
37917
38252
  "domains",
38253
+ "require_sso",
38254
+ "auto_join",
37918
38255
  "admins",
37919
38256
  "account",
37920
38257
  "createdAt"
@@ -37972,6 +38309,34 @@
37972
38309
  },
37973
38310
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
37974
38311
  },
38312
+ "require_sso": {
38313
+ "type": "boolean",
38314
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
38315
+ },
38316
+ "auto_join": {
38317
+ "type": "array",
38318
+ "items": {
38319
+ "type": "object",
38320
+ "required": [
38321
+ "team",
38322
+ "roles"
38323
+ ],
38324
+ "properties": {
38325
+ "team": {
38326
+ "type": "string",
38327
+ "description": "A team of this organization."
38328
+ },
38329
+ "roles": {
38330
+ "type": "array",
38331
+ "items": {
38332
+ "type": "string"
38333
+ },
38334
+ "description": "Role ids the member gets in that team."
38335
+ }
38336
+ }
38337
+ },
38338
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
38339
+ },
37975
38340
  "admins": {
37976
38341
  "type": "array",
37977
38342
  "items": {
@@ -38327,6 +38692,8 @@
38327
38692
  "description",
38328
38693
  "logo_url",
38329
38694
  "domains",
38695
+ "require_sso",
38696
+ "auto_join",
38330
38697
  "admins",
38331
38698
  "account",
38332
38699
  "createdAt"
@@ -38384,6 +38751,34 @@
38384
38751
  },
38385
38752
  "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
38386
38753
  },
38754
+ "require_sso": {
38755
+ "type": "boolean",
38756
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
38757
+ },
38758
+ "auto_join": {
38759
+ "type": "array",
38760
+ "items": {
38761
+ "type": "object",
38762
+ "required": [
38763
+ "team",
38764
+ "roles"
38765
+ ],
38766
+ "properties": {
38767
+ "team": {
38768
+ "type": "string",
38769
+ "description": "A team of this organization."
38770
+ },
38771
+ "roles": {
38772
+ "type": "array",
38773
+ "items": {
38774
+ "type": "string"
38775
+ },
38776
+ "description": "Role ids the member gets in that team."
38777
+ }
38778
+ }
38779
+ },
38780
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
38781
+ },
38387
38782
  "admins": {
38388
38783
  "type": "array",
38389
38784
  "items": {
@@ -38573,6 +38968,794 @@
38573
38968
  }
38574
38969
  }
38575
38970
  },
38971
+ "/organization/{organization_id}/auto-join": {
38972
+ "put": {
38973
+ "operationId": "organization/setAutoJoin",
38974
+ "summary": "Set an Organization's auto-join rules",
38975
+ "tags": [
38976
+ "organization"
38977
+ ],
38978
+ "description": "Replaces the auto-join rules: whoever signs in with a verified email of one of the verified domains joins these teams (of this organization) with these roles. Nobody already a member is changed. Pro plan to turn it on; an empty list turns it off and is always allowed.",
38979
+ "requestBody": {
38980
+ "required": true,
38981
+ "content": {
38982
+ "application/json": {
38983
+ "schema": {
38984
+ "type": "object",
38985
+ "required": [
38986
+ "auto_join"
38987
+ ],
38988
+ "properties": {
38989
+ "auto_join": {
38990
+ "type": "array",
38991
+ "items": {
38992
+ "type": "object",
38993
+ "required": [
38994
+ "team",
38995
+ "roles"
38996
+ ],
38997
+ "properties": {
38998
+ "team": {
38999
+ "type": "string",
39000
+ "description": "A team of this organization."
39001
+ },
39002
+ "roles": {
39003
+ "type": "array",
39004
+ "items": {
39005
+ "type": "string"
39006
+ },
39007
+ "description": "Role ids of this tenant."
39008
+ }
39009
+ },
39010
+ "additionalProperties": false
39011
+ },
39012
+ "maxItems": 50
39013
+ }
39014
+ },
39015
+ "additionalProperties": false
39016
+ }
39017
+ }
39018
+ }
39019
+ },
39020
+ "parameters": [
39021
+ {
39022
+ "schema": {
39023
+ "type": "string"
39024
+ },
39025
+ "in": "path",
39026
+ "name": "organization_id",
39027
+ "required": true
39028
+ }
39029
+ ],
39030
+ "security": [
39031
+ {
39032
+ "bearerAuth": []
39033
+ }
39034
+ ],
39035
+ "responses": {
39036
+ "200": {
39037
+ "description": "Organization",
39038
+ "content": {
39039
+ "application/json": {
39040
+ "schema": {
39041
+ "type": "object",
39042
+ "required": [
39043
+ "id",
39044
+ "name",
39045
+ "slug",
39046
+ "description",
39047
+ "logo_url",
39048
+ "domains",
39049
+ "require_sso",
39050
+ "auto_join",
39051
+ "admins",
39052
+ "account",
39053
+ "createdAt"
39054
+ ],
39055
+ "properties": {
39056
+ "id": {
39057
+ "type": "string",
39058
+ "description": "Organization ID"
39059
+ },
39060
+ "name": {
39061
+ "type": "string",
39062
+ "description": "Human-readable name of the organization.",
39063
+ "example": "Acme Inc."
39064
+ },
39065
+ "slug": {
39066
+ "type": "string",
39067
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
39068
+ "example": "acme-inc"
39069
+ },
39070
+ "description": {
39071
+ "type": "string",
39072
+ "description": "Optional free-form description.",
39073
+ "nullable": true
39074
+ },
39075
+ "logo_url": {
39076
+ "type": "string",
39077
+ "description": "Optional URL of the organization logo.",
39078
+ "nullable": true
39079
+ },
39080
+ "domains": {
39081
+ "type": "array",
39082
+ "items": {
39083
+ "type": "object",
39084
+ "required": [
39085
+ "domain",
39086
+ "verification_token",
39087
+ "verified_at"
39088
+ ],
39089
+ "properties": {
39090
+ "domain": {
39091
+ "type": "string",
39092
+ "example": "acme.com"
39093
+ },
39094
+ "verification_token": {
39095
+ "type": "string",
39096
+ "description": "Put `faable-verification=<verification_token>` in a TXT record at `_faable-challenge.<domain>`, then call `POST /organization/{organization_id}/domain/{domain}/verify`."
39097
+ },
39098
+ "verified_at": {
39099
+ "type": "string",
39100
+ "format": "date-time",
39101
+ "description": "When the TXT record was found. `null` = not verified.",
39102
+ "nullable": true
39103
+ }
39104
+ }
39105
+ },
39106
+ "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
39107
+ },
39108
+ "require_sso": {
39109
+ "type": "boolean",
39110
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
39111
+ },
39112
+ "auto_join": {
39113
+ "type": "array",
39114
+ "items": {
39115
+ "type": "object",
39116
+ "required": [
39117
+ "team",
39118
+ "roles"
39119
+ ],
39120
+ "properties": {
39121
+ "team": {
39122
+ "type": "string",
39123
+ "description": "A team of this organization."
39124
+ },
39125
+ "roles": {
39126
+ "type": "array",
39127
+ "items": {
39128
+ "type": "string"
39129
+ },
39130
+ "description": "Role ids the member gets in that team."
39131
+ }
39132
+ }
39133
+ },
39134
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
39135
+ },
39136
+ "admins": {
39137
+ "type": "array",
39138
+ "items": {
39139
+ "type": "string"
39140
+ },
39141
+ "description": "Ids of the users who manage the organization: its teams and its identity settings. Being an admin does not grant access to any team; team access is team membership."
39142
+ },
39143
+ "account": {
39144
+ "type": "string",
39145
+ "description": "Object is related with this account"
39146
+ },
39147
+ "metadata": {
39148
+ "type": "object",
39149
+ "properties": {},
39150
+ "additionalProperties": true,
39151
+ "description": "OrganizationMetadata",
39152
+ "default": {}
39153
+ },
39154
+ "createdAt": {
39155
+ "type": "string",
39156
+ "description": "Organization creation date"
39157
+ },
39158
+ "updatedAt": {
39159
+ "type": "string",
39160
+ "description": "Organization updated date"
39161
+ }
39162
+ },
39163
+ "description": "Organization"
39164
+ }
39165
+ }
39166
+ }
39167
+ },
39168
+ "400": {
39169
+ "description": "`team_not_in_organization` — Auto-join can only put people in teams of the same organization. `details.teams` lists the others.\n\n`invalid_role` — The role belongs to another account.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
39170
+ "content": {
39171
+ "application/json": {
39172
+ "schema": {
39173
+ "allOf": [
39174
+ {
39175
+ "$ref": "#/components/schemas/ErrorResponse"
39176
+ },
39177
+ {
39178
+ "type": "object",
39179
+ "properties": {
39180
+ "error_code": {
39181
+ "type": "string",
39182
+ "enum": [
39183
+ "team_not_in_organization",
39184
+ "invalid_role",
39185
+ "validation_error"
39186
+ ]
39187
+ }
39188
+ }
39189
+ }
39190
+ ]
39191
+ }
39192
+ }
39193
+ }
39194
+ },
39195
+ "401": {
39196
+ "description": "`unauthorized` — The request carries no valid credentials.",
39197
+ "content": {
39198
+ "application/json": {
39199
+ "schema": {
39200
+ "allOf": [
39201
+ {
39202
+ "$ref": "#/components/schemas/ErrorResponse"
39203
+ },
39204
+ {
39205
+ "type": "object",
39206
+ "properties": {
39207
+ "error_code": {
39208
+ "type": "string",
39209
+ "enum": [
39210
+ "unauthorized"
39211
+ ]
39212
+ }
39213
+ }
39214
+ }
39215
+ ]
39216
+ }
39217
+ }
39218
+ }
39219
+ },
39220
+ "402": {
39221
+ "description": "`plan_required` — The setting requires a higher plan. `message` says which.",
39222
+ "content": {
39223
+ "application/json": {
39224
+ "schema": {
39225
+ "allOf": [
39226
+ {
39227
+ "$ref": "#/components/schemas/ErrorResponse"
39228
+ },
39229
+ {
39230
+ "type": "object",
39231
+ "properties": {
39232
+ "error_code": {
39233
+ "type": "string",
39234
+ "enum": [
39235
+ "plan_required"
39236
+ ]
39237
+ }
39238
+ }
39239
+ }
39240
+ ]
39241
+ }
39242
+ }
39243
+ }
39244
+ },
39245
+ "403": {
39246
+ "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.",
39247
+ "content": {
39248
+ "application/json": {
39249
+ "schema": {
39250
+ "allOf": [
39251
+ {
39252
+ "$ref": "#/components/schemas/ErrorResponse"
39253
+ },
39254
+ {
39255
+ "type": "object",
39256
+ "properties": {
39257
+ "error_code": {
39258
+ "type": "string",
39259
+ "enum": [
39260
+ "forbidden",
39261
+ "insufficient_scope",
39262
+ "user_suspended"
39263
+ ]
39264
+ }
39265
+ }
39266
+ }
39267
+ ]
39268
+ }
39269
+ }
39270
+ }
39271
+ },
39272
+ "404": {
39273
+ "description": "`organization_not_found` — No organization with that id in this account.\n\n`role_not_found` — No role with that id in this account.\n\n`account_not_found` — No Auth Account matches the request (domain, header or token).",
39274
+ "content": {
39275
+ "application/json": {
39276
+ "schema": {
39277
+ "allOf": [
39278
+ {
39279
+ "$ref": "#/components/schemas/ErrorResponse"
39280
+ },
39281
+ {
39282
+ "type": "object",
39283
+ "properties": {
39284
+ "error_code": {
39285
+ "type": "string",
39286
+ "enum": [
39287
+ "organization_not_found",
39288
+ "role_not_found",
39289
+ "account_not_found"
39290
+ ]
39291
+ }
39292
+ }
39293
+ }
39294
+ ]
39295
+ }
39296
+ }
39297
+ }
39298
+ },
39299
+ "429": {
39300
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
39301
+ "content": {
39302
+ "application/json": {
39303
+ "schema": {
39304
+ "allOf": [
39305
+ {
39306
+ "$ref": "#/components/schemas/ErrorResponse"
39307
+ },
39308
+ {
39309
+ "type": "object",
39310
+ "properties": {
39311
+ "error_code": {
39312
+ "type": "string",
39313
+ "enum": [
39314
+ "too_many_requests"
39315
+ ]
39316
+ }
39317
+ }
39318
+ }
39319
+ ]
39320
+ }
39321
+ }
39322
+ }
39323
+ },
39324
+ "500": {
39325
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
39326
+ "content": {
39327
+ "application/json": {
39328
+ "schema": {
39329
+ "allOf": [
39330
+ {
39331
+ "$ref": "#/components/schemas/ErrorResponse"
39332
+ },
39333
+ {
39334
+ "type": "object",
39335
+ "properties": {
39336
+ "error_code": {
39337
+ "type": "string",
39338
+ "enum": [
39339
+ "internal_error"
39340
+ ]
39341
+ }
39342
+ }
39343
+ }
39344
+ ]
39345
+ }
39346
+ }
39347
+ }
39348
+ },
39349
+ "503": {
39350
+ "description": "`plan_unavailable` — The plan could not be checked right now, and this setting is only for paid plans. Try again in a minute.",
39351
+ "content": {
39352
+ "application/json": {
39353
+ "schema": {
39354
+ "allOf": [
39355
+ {
39356
+ "$ref": "#/components/schemas/ErrorResponse"
39357
+ },
39358
+ {
39359
+ "type": "object",
39360
+ "properties": {
39361
+ "error_code": {
39362
+ "type": "string",
39363
+ "enum": [
39364
+ "plan_unavailable"
39365
+ ]
39366
+ }
39367
+ }
39368
+ }
39369
+ ]
39370
+ }
39371
+ }
39372
+ }
39373
+ }
39374
+ }
39375
+ }
39376
+ },
39377
+ "/organization/{organization_id}/require-sso": {
39378
+ "put": {
39379
+ "operationId": "organization/setRequireSso",
39380
+ "summary": "Require SSO for an Organization",
39381
+ "tags": [
39382
+ "organization"
39383
+ ],
39384
+ "description": "On: people of the verified domains reach the organization's teams only through its identity provider. Access tokens carry `https://faable.com/org` (the organization of the user's verified email domain) and `https://faable.com/org_sso` (whether this session came through its identity provider); the resource server applies it. Needs a bound `oidc` connection and the Pro plan; turning it off is always allowed.",
39385
+ "requestBody": {
39386
+ "required": true,
39387
+ "content": {
39388
+ "application/json": {
39389
+ "schema": {
39390
+ "type": "object",
39391
+ "required": [
39392
+ "require_sso"
39393
+ ],
39394
+ "properties": {
39395
+ "require_sso": {
39396
+ "type": "boolean"
39397
+ }
39398
+ },
39399
+ "additionalProperties": false
39400
+ }
39401
+ }
39402
+ }
39403
+ },
39404
+ "parameters": [
39405
+ {
39406
+ "schema": {
39407
+ "type": "string"
39408
+ },
39409
+ "in": "path",
39410
+ "name": "organization_id",
39411
+ "required": true
39412
+ }
39413
+ ],
39414
+ "security": [
39415
+ {
39416
+ "bearerAuth": []
39417
+ }
39418
+ ],
39419
+ "responses": {
39420
+ "200": {
39421
+ "description": "Organization",
39422
+ "content": {
39423
+ "application/json": {
39424
+ "schema": {
39425
+ "type": "object",
39426
+ "required": [
39427
+ "id",
39428
+ "name",
39429
+ "slug",
39430
+ "description",
39431
+ "logo_url",
39432
+ "domains",
39433
+ "require_sso",
39434
+ "auto_join",
39435
+ "admins",
39436
+ "account",
39437
+ "createdAt"
39438
+ ],
39439
+ "properties": {
39440
+ "id": {
39441
+ "type": "string",
39442
+ "description": "Organization ID"
39443
+ },
39444
+ "name": {
39445
+ "type": "string",
39446
+ "description": "Human-readable name of the organization.",
39447
+ "example": "Acme Inc."
39448
+ },
39449
+ "slug": {
39450
+ "type": "string",
39451
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
39452
+ "example": "acme-inc"
39453
+ },
39454
+ "description": {
39455
+ "type": "string",
39456
+ "description": "Optional free-form description.",
39457
+ "nullable": true
39458
+ },
39459
+ "logo_url": {
39460
+ "type": "string",
39461
+ "description": "Optional URL of the organization logo.",
39462
+ "nullable": true
39463
+ },
39464
+ "domains": {
39465
+ "type": "array",
39466
+ "items": {
39467
+ "type": "object",
39468
+ "required": [
39469
+ "domain",
39470
+ "verification_token",
39471
+ "verified_at"
39472
+ ],
39473
+ "properties": {
39474
+ "domain": {
39475
+ "type": "string",
39476
+ "example": "acme.com"
39477
+ },
39478
+ "verification_token": {
39479
+ "type": "string",
39480
+ "description": "Put `faable-verification=<verification_token>` in a TXT record at `_faable-challenge.<domain>`, then call `POST /organization/{organization_id}/domain/{domain}/verify`."
39481
+ },
39482
+ "verified_at": {
39483
+ "type": "string",
39484
+ "format": "date-time",
39485
+ "description": "When the TXT record was found. `null` = not verified.",
39486
+ "nullable": true
39487
+ }
39488
+ }
39489
+ },
39490
+ "description": "Email domains the organization claims. Only a verified one counts: it is how the organization's people are recognized."
39491
+ },
39492
+ "require_sso": {
39493
+ "type": "boolean",
39494
+ "description": "People of the verified domains reach the organization's teams only through its identity provider. Applied by the resource server with the `https://faable.com/org` and `https://faable.com/org_sso` access-token claims."
39495
+ },
39496
+ "auto_join": {
39497
+ "type": "array",
39498
+ "items": {
39499
+ "type": "object",
39500
+ "required": [
39501
+ "team",
39502
+ "roles"
39503
+ ],
39504
+ "properties": {
39505
+ "team": {
39506
+ "type": "string",
39507
+ "description": "A team of this organization."
39508
+ },
39509
+ "roles": {
39510
+ "type": "array",
39511
+ "items": {
39512
+ "type": "string"
39513
+ },
39514
+ "description": "Role ids the member gets in that team."
39515
+ }
39516
+ }
39517
+ },
39518
+ "description": "Whoever signs in with a verified email of one of the verified domains joins these teams. Empty = nobody joins by domain."
39519
+ },
39520
+ "admins": {
39521
+ "type": "array",
39522
+ "items": {
39523
+ "type": "string"
39524
+ },
39525
+ "description": "Ids of the users who manage the organization: its teams and its identity settings. Being an admin does not grant access to any team; team access is team membership."
39526
+ },
39527
+ "account": {
39528
+ "type": "string",
39529
+ "description": "Object is related with this account"
39530
+ },
39531
+ "metadata": {
39532
+ "type": "object",
39533
+ "properties": {},
39534
+ "additionalProperties": true,
39535
+ "description": "OrganizationMetadata",
39536
+ "default": {}
39537
+ },
39538
+ "createdAt": {
39539
+ "type": "string",
39540
+ "description": "Organization creation date"
39541
+ },
39542
+ "updatedAt": {
39543
+ "type": "string",
39544
+ "description": "Organization updated date"
39545
+ }
39546
+ },
39547
+ "description": "Organization"
39548
+ }
39549
+ }
39550
+ }
39551
+ },
39552
+ "400": {
39553
+ "description": "`organization_has_no_idp` — Requiring SSO needs an identity provider: bind an `oidc` connection to the organization first.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
39554
+ "content": {
39555
+ "application/json": {
39556
+ "schema": {
39557
+ "allOf": [
39558
+ {
39559
+ "$ref": "#/components/schemas/ErrorResponse"
39560
+ },
39561
+ {
39562
+ "type": "object",
39563
+ "properties": {
39564
+ "error_code": {
39565
+ "type": "string",
39566
+ "enum": [
39567
+ "organization_has_no_idp",
39568
+ "validation_error"
39569
+ ]
39570
+ }
39571
+ }
39572
+ }
39573
+ ]
39574
+ }
39575
+ }
39576
+ }
39577
+ },
39578
+ "401": {
39579
+ "description": "`unauthorized` — The request carries no valid credentials.",
39580
+ "content": {
39581
+ "application/json": {
39582
+ "schema": {
39583
+ "allOf": [
39584
+ {
39585
+ "$ref": "#/components/schemas/ErrorResponse"
39586
+ },
39587
+ {
39588
+ "type": "object",
39589
+ "properties": {
39590
+ "error_code": {
39591
+ "type": "string",
39592
+ "enum": [
39593
+ "unauthorized"
39594
+ ]
39595
+ }
39596
+ }
39597
+ }
39598
+ ]
39599
+ }
39600
+ }
39601
+ }
39602
+ },
39603
+ "402": {
39604
+ "description": "`plan_required` — The setting requires a higher plan. `message` says which.",
39605
+ "content": {
39606
+ "application/json": {
39607
+ "schema": {
39608
+ "allOf": [
39609
+ {
39610
+ "$ref": "#/components/schemas/ErrorResponse"
39611
+ },
39612
+ {
39613
+ "type": "object",
39614
+ "properties": {
39615
+ "error_code": {
39616
+ "type": "string",
39617
+ "enum": [
39618
+ "plan_required"
39619
+ ]
39620
+ }
39621
+ }
39622
+ }
39623
+ ]
39624
+ }
39625
+ }
39626
+ }
39627
+ },
39628
+ "403": {
39629
+ "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.",
39630
+ "content": {
39631
+ "application/json": {
39632
+ "schema": {
39633
+ "allOf": [
39634
+ {
39635
+ "$ref": "#/components/schemas/ErrorResponse"
39636
+ },
39637
+ {
39638
+ "type": "object",
39639
+ "properties": {
39640
+ "error_code": {
39641
+ "type": "string",
39642
+ "enum": [
39643
+ "forbidden",
39644
+ "insufficient_scope",
39645
+ "user_suspended"
39646
+ ]
39647
+ }
39648
+ }
39649
+ }
39650
+ ]
39651
+ }
39652
+ }
39653
+ }
39654
+ },
39655
+ "404": {
39656
+ "description": "`organization_not_found` — No organization with that id in this account.\n\n`account_not_found` — No Auth Account matches the request (domain, header or token).",
39657
+ "content": {
39658
+ "application/json": {
39659
+ "schema": {
39660
+ "allOf": [
39661
+ {
39662
+ "$ref": "#/components/schemas/ErrorResponse"
39663
+ },
39664
+ {
39665
+ "type": "object",
39666
+ "properties": {
39667
+ "error_code": {
39668
+ "type": "string",
39669
+ "enum": [
39670
+ "organization_not_found",
39671
+ "account_not_found"
39672
+ ]
39673
+ }
39674
+ }
39675
+ }
39676
+ ]
39677
+ }
39678
+ }
39679
+ }
39680
+ },
39681
+ "429": {
39682
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
39683
+ "content": {
39684
+ "application/json": {
39685
+ "schema": {
39686
+ "allOf": [
39687
+ {
39688
+ "$ref": "#/components/schemas/ErrorResponse"
39689
+ },
39690
+ {
39691
+ "type": "object",
39692
+ "properties": {
39693
+ "error_code": {
39694
+ "type": "string",
39695
+ "enum": [
39696
+ "too_many_requests"
39697
+ ]
39698
+ }
39699
+ }
39700
+ }
39701
+ ]
39702
+ }
39703
+ }
39704
+ }
39705
+ },
39706
+ "500": {
39707
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
39708
+ "content": {
39709
+ "application/json": {
39710
+ "schema": {
39711
+ "allOf": [
39712
+ {
39713
+ "$ref": "#/components/schemas/ErrorResponse"
39714
+ },
39715
+ {
39716
+ "type": "object",
39717
+ "properties": {
39718
+ "error_code": {
39719
+ "type": "string",
39720
+ "enum": [
39721
+ "internal_error"
39722
+ ]
39723
+ }
39724
+ }
39725
+ }
39726
+ ]
39727
+ }
39728
+ }
39729
+ }
39730
+ },
39731
+ "503": {
39732
+ "description": "`plan_unavailable` — The plan could not be checked right now, and this setting is only for paid plans. Try again in a minute.",
39733
+ "content": {
39734
+ "application/json": {
39735
+ "schema": {
39736
+ "allOf": [
39737
+ {
39738
+ "$ref": "#/components/schemas/ErrorResponse"
39739
+ },
39740
+ {
39741
+ "type": "object",
39742
+ "properties": {
39743
+ "error_code": {
39744
+ "type": "string",
39745
+ "enum": [
39746
+ "plan_unavailable"
39747
+ ]
39748
+ }
39749
+ }
39750
+ }
39751
+ ]
39752
+ }
39753
+ }
39754
+ }
39755
+ }
39756
+ }
39757
+ }
39758
+ },
38576
39759
  "/teammember": {
38577
39760
  "get": {
38578
39761
  "operationId": "teammember/list",