@faable/auth-sdk 2.7.81 → 2.7.82

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.64.0",
6
+ "version": "2.65.0",
7
7
  "license": {
8
8
  "name": "private",
9
9
  "url": "https://faable.com/docs/platform/privacy-policy"
@@ -532,6 +532,10 @@
532
532
  "type": "boolean",
533
533
  "description": "When true, `/logout` asks the End-User to confirm before ending the session unless the request carries a verified `id_token_hint`. Off by default — a plain link to `/logout` is otherwise enough to sign anyone out (logout CSRF)."
534
534
  },
535
+ "dynamic_client_registration_enabled": {
536
+ "type": "boolean",
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
+ },
535
539
  "canonical_host": {
536
540
  "type": "string",
537
541
  "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.",
@@ -3569,6 +3573,11 @@
3569
3573
  "description": "Optional URL of an image used as the team avatar/logo.",
3570
3574
  "nullable": true
3571
3575
  },
3576
+ "organization": {
3577
+ "type": "string",
3578
+ "description": "Id of the Organization the team belongs to, or `null`. Changed only with `PUT /team/{team_id}/organization`.",
3579
+ "nullable": true
3580
+ },
3572
3581
  "account": {
3573
3582
  "type": "string",
3574
3583
  "description": "Object is related with this account"
@@ -3656,6 +3665,158 @@
3656
3665
  "additionalProperties": true,
3657
3666
  "description": "Arbitrary key/value pairs attached to the team. Replaces the previous metadata entirely."
3658
3667
  },
3668
+ "Organization": {
3669
+ "type": "object",
3670
+ "required": [
3671
+ "id",
3672
+ "name",
3673
+ "slug",
3674
+ "description",
3675
+ "logo_url",
3676
+ "admins",
3677
+ "account",
3678
+ "createdAt"
3679
+ ],
3680
+ "properties": {
3681
+ "id": {
3682
+ "type": "string",
3683
+ "description": "Organization ID"
3684
+ },
3685
+ "name": {
3686
+ "type": "string",
3687
+ "description": "Human-readable name of the organization.",
3688
+ "example": "Acme Inc."
3689
+ },
3690
+ "slug": {
3691
+ "type": "string",
3692
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
3693
+ "example": "acme-inc"
3694
+ },
3695
+ "description": {
3696
+ "type": "string",
3697
+ "description": "Optional free-form description.",
3698
+ "nullable": true
3699
+ },
3700
+ "logo_url": {
3701
+ "type": "string",
3702
+ "description": "Optional URL of the organization logo.",
3703
+ "nullable": true
3704
+ },
3705
+ "admins": {
3706
+ "type": "array",
3707
+ "items": {
3708
+ "type": "string"
3709
+ },
3710
+ "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."
3711
+ },
3712
+ "account": {
3713
+ "type": "string",
3714
+ "description": "Object is related with this account"
3715
+ },
3716
+ "metadata": {
3717
+ "type": "object",
3718
+ "properties": {},
3719
+ "additionalProperties": true,
3720
+ "description": "OrganizationMetadata",
3721
+ "default": {}
3722
+ },
3723
+ "createdAt": {
3724
+ "type": "string",
3725
+ "description": "Organization creation date"
3726
+ },
3727
+ "updatedAt": {
3728
+ "type": "string",
3729
+ "description": "Organization updated date"
3730
+ }
3731
+ },
3732
+ "description": "Organization"
3733
+ },
3734
+ "OrganizationMetadata": {
3735
+ "type": "object",
3736
+ "properties": {},
3737
+ "additionalProperties": true,
3738
+ "description": "OrganizationMetadata",
3739
+ "default": {}
3740
+ },
3741
+ "OrganizationCreate": {
3742
+ "type": "object",
3743
+ "required": [
3744
+ "name"
3745
+ ],
3746
+ "properties": {
3747
+ "name": {
3748
+ "type": "string",
3749
+ "minLength": 1,
3750
+ "description": "Human-readable name of the organization.",
3751
+ "example": "Acme Inc."
3752
+ },
3753
+ "description": {
3754
+ "type": "string",
3755
+ "description": "Optional free-form description."
3756
+ },
3757
+ "logo_url": {
3758
+ "type": "string",
3759
+ "format": "uri",
3760
+ "description": "Optional URL of the organization logo."
3761
+ },
3762
+ "admins": {
3763
+ "type": "array",
3764
+ "items": {
3765
+ "type": "string",
3766
+ "pattern": "^user_[0-9a-f]{24}$"
3767
+ },
3768
+ "uniqueItems": true,
3769
+ "description": "Initial admins (user ids of this tenant). Can be empty and filled later with `POST /organization/{organization_id}/admin`."
3770
+ },
3771
+ "metadata": {
3772
+ "type": "object",
3773
+ "properties": {},
3774
+ "additionalProperties": true,
3775
+ "description": "Add Metadata"
3776
+ }
3777
+ },
3778
+ "description": "OrganizationCreate",
3779
+ "additionalProperties": false
3780
+ },
3781
+ "OrganizationMetadataCreate": {
3782
+ "type": "object",
3783
+ "properties": {},
3784
+ "additionalProperties": true,
3785
+ "description": "Add Metadata"
3786
+ },
3787
+ "OrganizationUpdate": {
3788
+ "type": "object",
3789
+ "properties": {
3790
+ "name": {
3791
+ "type": "string",
3792
+ "minLength": 1,
3793
+ "description": "New human-readable name."
3794
+ },
3795
+ "description": {
3796
+ "type": "string",
3797
+ "description": "New free-form description."
3798
+ },
3799
+ "logo_url": {
3800
+ "type": "string",
3801
+ "format": "uri",
3802
+ "description": "New URL of the organization logo."
3803
+ },
3804
+ "metadata": {
3805
+ "type": "object",
3806
+ "properties": {},
3807
+ "additionalProperties": true,
3808
+ "description": "Arbitrary key/value pairs. Replaces the previous metadata entirely."
3809
+ }
3810
+ },
3811
+ "description": "Partial update for an Organization. `slug` is derived from `name` on creation and is not editable; admins change through `/organization/{organization_id}/admin`.",
3812
+ "additionalProperties": false
3813
+ },
3814
+ "OrganizationUpdateMetadata": {
3815
+ "type": "object",
3816
+ "properties": {},
3817
+ "additionalProperties": true,
3818
+ "description": "Arbitrary key/value pairs. Replaces the previous metadata entirely."
3819
+ },
3659
3820
  "TeamMember": {
3660
3821
  "type": "object",
3661
3822
  "required": [
@@ -5301,7 +5462,7 @@
5301
5462
  "items": {
5302
5463
  "type": "string"
5303
5464
  },
5304
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
5465
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
5305
5466
  },
5306
5467
  "channel": {
5307
5468
  "type": "string",
@@ -5506,7 +5667,7 @@
5506
5667
  "items": {
5507
5668
  "type": "string"
5508
5669
  },
5509
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
5670
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
5510
5671
  },
5511
5672
  "channel": {
5512
5673
  "type": "string",
@@ -5683,7 +5844,7 @@
5683
5844
  "items": {
5684
5845
  "type": "string"
5685
5846
  },
5686
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
5847
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
5687
5848
  },
5688
5849
  "channel": {
5689
5850
  "type": "string",
@@ -5815,7 +5976,7 @@
5815
5976
  "items": {
5816
5977
  "type": "string"
5817
5978
  },
5818
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
5979
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
5819
5980
  },
5820
5981
  "channel": {
5821
5982
  "type": "string",
@@ -5932,7 +6093,7 @@
5932
6093
  "items": {
5933
6094
  "type": "string"
5934
6095
  },
5935
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
6096
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
5936
6097
  },
5937
6098
  "channel": {
5938
6099
  "type": "string",
@@ -7280,6 +7441,10 @@
7280
7441
  }
7281
7442
  ]
7282
7443
  },
7444
+ "dynamic_client_registration_enabled": {
7445
+ "type": "boolean",
7446
+ "nullable": true
7447
+ },
7283
7448
  "canonical_host": {
7284
7449
  "type": "string",
7285
7450
  "nullable": true
@@ -7615,7 +7780,7 @@
7615
7780
  },
7616
7781
  "ErrorCode": {
7617
7782
  "type": "string",
7618
- "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- `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.",
7783
+ "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- `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.",
7619
7784
  "enum": [
7620
7785
  "bad_request",
7621
7786
  "validation_error",
@@ -7735,6 +7900,11 @@
7735
7900
  "invite_used",
7736
7901
  "already_member",
7737
7902
  "not_a_member",
7903
+ "registration_disabled",
7904
+ "organization_not_found",
7905
+ "invalid_user",
7906
+ "not_an_organization_admin",
7907
+ "last_organization_admin",
7738
7908
  "team_id_unavailable",
7739
7909
  "use_team_member_route",
7740
7910
  "role_not_found",
@@ -8398,6 +8568,10 @@
8398
8568
  "type": "boolean",
8399
8569
  "description": "When true, `/logout` asks the End-User to confirm before ending the session unless the request carries a verified `id_token_hint`. Off by default — a plain link to `/logout` is otherwise enough to sign anyone out (logout CSRF)."
8400
8570
  },
8571
+ "dynamic_client_registration_enabled": {
8572
+ "type": "boolean",
8573
+ "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`."
8574
+ },
8401
8575
  "canonical_host": {
8402
8576
  "type": "string",
8403
8577
  "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.",
@@ -9142,6 +9316,10 @@
9142
9316
  "type": "boolean",
9143
9317
  "description": "When true, `/logout` asks the End-User to confirm before ending the session unless the request carries a verified `id_token_hint`. Off by default — a plain link to `/logout` is otherwise enough to sign anyone out (logout CSRF)."
9144
9318
  },
9319
+ "dynamic_client_registration_enabled": {
9320
+ "type": "boolean",
9321
+ "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`."
9322
+ },
9145
9323
  "canonical_host": {
9146
9324
  "type": "string",
9147
9325
  "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.",
@@ -10123,6 +10301,10 @@
10123
10301
  "type": "boolean",
10124
10302
  "description": "When true, `/logout` asks the End-User to confirm before ending the session unless the request carries a verified `id_token_hint`. Off by default — a plain link to `/logout` is otherwise enough to sign anyone out (logout CSRF)."
10125
10303
  },
10304
+ "dynamic_client_registration_enabled": {
10305
+ "type": "boolean",
10306
+ "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`."
10307
+ },
10126
10308
  "canonical_host": {
10127
10309
  "type": "string",
10128
10310
  "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.",
@@ -10748,6 +10930,10 @@
10748
10930
  }
10749
10931
  ]
10750
10932
  },
10933
+ "dynamic_client_registration_enabled": {
10934
+ "type": "boolean",
10935
+ "nullable": true
10936
+ },
10751
10937
  "canonical_host": {
10752
10938
  "type": "string",
10753
10939
  "nullable": true
@@ -11280,6 +11466,10 @@
11280
11466
  "type": "boolean",
11281
11467
  "description": "When true, `/logout` asks the End-User to confirm before ending the session unless the request carries a verified `id_token_hint`. Off by default — a plain link to `/logout` is otherwise enough to sign anyone out (logout CSRF)."
11282
11468
  },
11469
+ "dynamic_client_registration_enabled": {
11470
+ "type": "boolean",
11471
+ "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`."
11472
+ },
11283
11473
  "canonical_host": {
11284
11474
  "type": "string",
11285
11475
  "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.",
@@ -14222,6 +14412,10 @@
14222
14412
  "type": "boolean",
14223
14413
  "description": "When true, `/logout` asks the End-User to confirm before ending the session unless the request carries a verified `id_token_hint`. Off by default — a plain link to `/logout` is otherwise enough to sign anyone out (logout CSRF)."
14224
14414
  },
14415
+ "dynamic_client_registration_enabled": {
14416
+ "type": "boolean",
14417
+ "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`."
14418
+ },
14225
14419
  "canonical_host": {
14226
14420
  "type": "string",
14227
14421
  "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.",
@@ -32775,39 +32969,2248 @@
32775
32969
  }
32776
32970
  }
32777
32971
  },
32778
- "/rolemember/{rolemember_id}": {
32779
- "get": {
32780
- "operationId": "rolemember/get",
32781
- "summary": "Get Rolemember",
32972
+ "/rolemember/{rolemember_id}": {
32973
+ "get": {
32974
+ "operationId": "rolemember/get",
32975
+ "summary": "Get Rolemember",
32976
+ "tags": [
32977
+ "rolemember"
32978
+ ],
32979
+ "description": "Get Rolemember",
32980
+ "parameters": [
32981
+ {
32982
+ "schema": {
32983
+ "type": "array",
32984
+ "items": {
32985
+ "type": "string",
32986
+ "enum": [
32987
+ "user",
32988
+ "role"
32989
+ ],
32990
+ "description": "Allowed expand paths on `rolemember`: `user`, `role`."
32991
+ },
32992
+ "maxItems": 2
32993
+ },
32994
+ "in": "query",
32995
+ "name": "expand",
32996
+ "required": false,
32997
+ "description": "Expand id-only fields in the response. Pass one path per entry (e.g. `?expand=user`)."
32998
+ },
32999
+ {
33000
+ "schema": {
33001
+ "type": "string"
33002
+ },
33003
+ "in": "path",
33004
+ "name": "rolemember_id",
33005
+ "required": true
33006
+ }
33007
+ ],
33008
+ "security": [
33009
+ {
33010
+ "bearerAuth": []
33011
+ }
33012
+ ],
33013
+ "responses": {
33014
+ "200": {
33015
+ "description": "RoleMember",
33016
+ "content": {
33017
+ "application/json": {
33018
+ "schema": {
33019
+ "type": "object",
33020
+ "required": [
33021
+ "id",
33022
+ "role",
33023
+ "user",
33024
+ "account",
33025
+ "createdAt"
33026
+ ],
33027
+ "properties": {
33028
+ "id": {
33029
+ "type": "string",
33030
+ "description": "RoleMember ID"
33031
+ },
33032
+ "role": {
33033
+ "anyOf": [
33034
+ {
33035
+ "$ref": "#/components/schemas/Role"
33036
+ },
33037
+ {
33038
+ "type": "string"
33039
+ },
33040
+ {}
33041
+ ],
33042
+ "description": "Role granted to the user. Returned as an id by default; pass `?expand=role` to inline the full Role object."
33043
+ },
33044
+ "user": {
33045
+ "anyOf": [
33046
+ {
33047
+ "$ref": "#/components/schemas/User"
33048
+ },
33049
+ {
33050
+ "type": "string"
33051
+ },
33052
+ {}
33053
+ ],
33054
+ "description": "User the role is granted to. Returned as an id by default; pass `?expand=user` to inline the full User object."
33055
+ },
33056
+ "account": {
33057
+ "type": "string",
33058
+ "description": "Object is related with this account"
33059
+ },
33060
+ "metadata": {
33061
+ "type": "object",
33062
+ "properties": {},
33063
+ "additionalProperties": true,
33064
+ "description": "RoleMemberMetadata",
33065
+ "default": {}
33066
+ },
33067
+ "createdAt": {
33068
+ "type": "string",
33069
+ "description": "RoleMember creation date"
33070
+ },
33071
+ "updatedAt": {
33072
+ "type": "string",
33073
+ "description": "RoleMember updated date"
33074
+ }
33075
+ },
33076
+ "description": "RoleMember"
33077
+ }
33078
+ }
33079
+ }
33080
+ },
33081
+ "400": {
33082
+ "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.",
33083
+ "content": {
33084
+ "application/json": {
33085
+ "schema": {
33086
+ "allOf": [
33087
+ {
33088
+ "$ref": "#/components/schemas/ErrorResponse"
33089
+ },
33090
+ {
33091
+ "type": "object",
33092
+ "properties": {
33093
+ "error_code": {
33094
+ "type": "string",
33095
+ "enum": [
33096
+ "invalid_id",
33097
+ "invalid_expand",
33098
+ "validation_error"
33099
+ ]
33100
+ }
33101
+ }
33102
+ }
33103
+ ]
33104
+ }
33105
+ }
33106
+ }
33107
+ },
33108
+ "401": {
33109
+ "description": "`unauthorized` — The request carries no valid credentials.",
33110
+ "content": {
33111
+ "application/json": {
33112
+ "schema": {
33113
+ "allOf": [
33114
+ {
33115
+ "$ref": "#/components/schemas/ErrorResponse"
33116
+ },
33117
+ {
33118
+ "type": "object",
33119
+ "properties": {
33120
+ "error_code": {
33121
+ "type": "string",
33122
+ "enum": [
33123
+ "unauthorized"
33124
+ ]
33125
+ }
33126
+ }
33127
+ }
33128
+ ]
33129
+ }
33130
+ }
33131
+ }
33132
+ },
33133
+ "403": {
33134
+ "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.",
33135
+ "content": {
33136
+ "application/json": {
33137
+ "schema": {
33138
+ "allOf": [
33139
+ {
33140
+ "$ref": "#/components/schemas/ErrorResponse"
33141
+ },
33142
+ {
33143
+ "type": "object",
33144
+ "properties": {
33145
+ "error_code": {
33146
+ "type": "string",
33147
+ "enum": [
33148
+ "forbidden",
33149
+ "insufficient_scope",
33150
+ "user_suspended"
33151
+ ]
33152
+ }
33153
+ }
33154
+ }
33155
+ ]
33156
+ }
33157
+ }
33158
+ }
33159
+ },
33160
+ "404": {
33161
+ "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).",
33162
+ "content": {
33163
+ "application/json": {
33164
+ "schema": {
33165
+ "allOf": [
33166
+ {
33167
+ "$ref": "#/components/schemas/ErrorResponse"
33168
+ },
33169
+ {
33170
+ "type": "object",
33171
+ "properties": {
33172
+ "error_code": {
33173
+ "type": "string",
33174
+ "enum": [
33175
+ "not_found",
33176
+ "account_not_found"
33177
+ ]
33178
+ }
33179
+ }
33180
+ }
33181
+ ]
33182
+ }
33183
+ }
33184
+ }
33185
+ },
33186
+ "429": {
33187
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
33188
+ "content": {
33189
+ "application/json": {
33190
+ "schema": {
33191
+ "allOf": [
33192
+ {
33193
+ "$ref": "#/components/schemas/ErrorResponse"
33194
+ },
33195
+ {
33196
+ "type": "object",
33197
+ "properties": {
33198
+ "error_code": {
33199
+ "type": "string",
33200
+ "enum": [
33201
+ "too_many_requests"
33202
+ ]
33203
+ }
33204
+ }
33205
+ }
33206
+ ]
33207
+ }
33208
+ }
33209
+ }
33210
+ },
33211
+ "500": {
33212
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
33213
+ "content": {
33214
+ "application/json": {
33215
+ "schema": {
33216
+ "allOf": [
33217
+ {
33218
+ "$ref": "#/components/schemas/ErrorResponse"
33219
+ },
33220
+ {
33221
+ "type": "object",
33222
+ "properties": {
33223
+ "error_code": {
33224
+ "type": "string",
33225
+ "enum": [
33226
+ "internal_error"
33227
+ ]
33228
+ }
33229
+ }
33230
+ }
33231
+ ]
33232
+ }
33233
+ }
33234
+ }
33235
+ }
33236
+ }
33237
+ },
33238
+ "delete": {
33239
+ "operationId": "rolemember/delete",
33240
+ "summary": "Delete Rolemember",
33241
+ "tags": [
33242
+ "rolemember"
33243
+ ],
33244
+ "description": "Delete Rolemember",
33245
+ "parameters": [
33246
+ {
33247
+ "schema": {
33248
+ "type": "string"
33249
+ },
33250
+ "in": "path",
33251
+ "name": "rolemember_id",
33252
+ "required": true
33253
+ }
33254
+ ],
33255
+ "security": [
33256
+ {
33257
+ "bearerAuth": []
33258
+ }
33259
+ ],
33260
+ "responses": {
33261
+ "200": {
33262
+ "description": "RoleMember",
33263
+ "content": {
33264
+ "application/json": {
33265
+ "schema": {
33266
+ "type": "object",
33267
+ "required": [
33268
+ "id",
33269
+ "role",
33270
+ "user",
33271
+ "account",
33272
+ "createdAt"
33273
+ ],
33274
+ "properties": {
33275
+ "id": {
33276
+ "type": "string",
33277
+ "description": "RoleMember ID"
33278
+ },
33279
+ "role": {
33280
+ "anyOf": [
33281
+ {
33282
+ "$ref": "#/components/schemas/Role"
33283
+ },
33284
+ {
33285
+ "type": "string"
33286
+ },
33287
+ {}
33288
+ ],
33289
+ "description": "Role granted to the user. Returned as an id by default; pass `?expand=role` to inline the full Role object."
33290
+ },
33291
+ "user": {
33292
+ "anyOf": [
33293
+ {
33294
+ "$ref": "#/components/schemas/User"
33295
+ },
33296
+ {
33297
+ "type": "string"
33298
+ },
33299
+ {}
33300
+ ],
33301
+ "description": "User the role is granted to. Returned as an id by default; pass `?expand=user` to inline the full User object."
33302
+ },
33303
+ "account": {
33304
+ "type": "string",
33305
+ "description": "Object is related with this account"
33306
+ },
33307
+ "metadata": {
33308
+ "type": "object",
33309
+ "properties": {},
33310
+ "additionalProperties": true,
33311
+ "description": "RoleMemberMetadata",
33312
+ "default": {}
33313
+ },
33314
+ "createdAt": {
33315
+ "type": "string",
33316
+ "description": "RoleMember creation date"
33317
+ },
33318
+ "updatedAt": {
33319
+ "type": "string",
33320
+ "description": "RoleMember updated date"
33321
+ }
33322
+ },
33323
+ "description": "RoleMember"
33324
+ }
33325
+ }
33326
+ }
33327
+ },
33328
+ "400": {
33329
+ "description": "`invalid_id` — The id in the path is not a valid id for this resource.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
33330
+ "content": {
33331
+ "application/json": {
33332
+ "schema": {
33333
+ "allOf": [
33334
+ {
33335
+ "$ref": "#/components/schemas/ErrorResponse"
33336
+ },
33337
+ {
33338
+ "type": "object",
33339
+ "properties": {
33340
+ "error_code": {
33341
+ "type": "string",
33342
+ "enum": [
33343
+ "invalid_id",
33344
+ "validation_error"
33345
+ ]
33346
+ }
33347
+ }
33348
+ }
33349
+ ]
33350
+ }
33351
+ }
33352
+ }
33353
+ },
33354
+ "401": {
33355
+ "description": "`unauthorized` — The request carries no valid credentials.",
33356
+ "content": {
33357
+ "application/json": {
33358
+ "schema": {
33359
+ "allOf": [
33360
+ {
33361
+ "$ref": "#/components/schemas/ErrorResponse"
33362
+ },
33363
+ {
33364
+ "type": "object",
33365
+ "properties": {
33366
+ "error_code": {
33367
+ "type": "string",
33368
+ "enum": [
33369
+ "unauthorized"
33370
+ ]
33371
+ }
33372
+ }
33373
+ }
33374
+ ]
33375
+ }
33376
+ }
33377
+ }
33378
+ },
33379
+ "403": {
33380
+ "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.",
33381
+ "content": {
33382
+ "application/json": {
33383
+ "schema": {
33384
+ "allOf": [
33385
+ {
33386
+ "$ref": "#/components/schemas/ErrorResponse"
33387
+ },
33388
+ {
33389
+ "type": "object",
33390
+ "properties": {
33391
+ "error_code": {
33392
+ "type": "string",
33393
+ "enum": [
33394
+ "forbidden",
33395
+ "insufficient_scope",
33396
+ "user_suspended"
33397
+ ]
33398
+ }
33399
+ }
33400
+ }
33401
+ ]
33402
+ }
33403
+ }
33404
+ }
33405
+ },
33406
+ "404": {
33407
+ "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).",
33408
+ "content": {
33409
+ "application/json": {
33410
+ "schema": {
33411
+ "allOf": [
33412
+ {
33413
+ "$ref": "#/components/schemas/ErrorResponse"
33414
+ },
33415
+ {
33416
+ "type": "object",
33417
+ "properties": {
33418
+ "error_code": {
33419
+ "type": "string",
33420
+ "enum": [
33421
+ "not_found",
33422
+ "account_not_found"
33423
+ ]
33424
+ }
33425
+ }
33426
+ }
33427
+ ]
33428
+ }
33429
+ }
33430
+ }
33431
+ },
33432
+ "429": {
33433
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
33434
+ "content": {
33435
+ "application/json": {
33436
+ "schema": {
33437
+ "allOf": [
33438
+ {
33439
+ "$ref": "#/components/schemas/ErrorResponse"
33440
+ },
33441
+ {
33442
+ "type": "object",
33443
+ "properties": {
33444
+ "error_code": {
33445
+ "type": "string",
33446
+ "enum": [
33447
+ "too_many_requests"
33448
+ ]
33449
+ }
33450
+ }
33451
+ }
33452
+ ]
33453
+ }
33454
+ }
33455
+ }
33456
+ },
33457
+ "500": {
33458
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
33459
+ "content": {
33460
+ "application/json": {
33461
+ "schema": {
33462
+ "allOf": [
33463
+ {
33464
+ "$ref": "#/components/schemas/ErrorResponse"
33465
+ },
33466
+ {
33467
+ "type": "object",
33468
+ "properties": {
33469
+ "error_code": {
33470
+ "type": "string",
33471
+ "enum": [
33472
+ "internal_error"
33473
+ ]
33474
+ }
33475
+ }
33476
+ }
33477
+ ]
33478
+ }
33479
+ }
33480
+ }
33481
+ }
33482
+ }
33483
+ }
33484
+ },
33485
+ "/team": {
33486
+ "get": {
33487
+ "operationId": "team/list",
33488
+ "summary": "List Teams",
33489
+ "tags": [
33490
+ "team"
33491
+ ],
33492
+ "description": "List Teams",
33493
+ "parameters": [
33494
+ {
33495
+ "schema": {
33496
+ "type": "number",
33497
+ "minimum": 1,
33498
+ "maximum": 200
33499
+ },
33500
+ "in": "query",
33501
+ "name": "pageSize",
33502
+ "required": false,
33503
+ "description": "Number of items per page (max 200)"
33504
+ },
33505
+ {
33506
+ "schema": {
33507
+ "type": "string"
33508
+ },
33509
+ "in": "query",
33510
+ "name": "cursor",
33511
+ "required": false,
33512
+ "description": "Cursor for next page"
33513
+ },
33514
+ {
33515
+ "schema": {
33516
+ "type": "string"
33517
+ },
33518
+ "in": "query",
33519
+ "name": "next",
33520
+ "required": false,
33521
+ "description": "Cursor returned by the previous page"
33522
+ },
33523
+ {
33524
+ "schema": {
33525
+ "type": "string"
33526
+ },
33527
+ "in": "query",
33528
+ "name": "query",
33529
+ "required": false,
33530
+ "description": "Filter using a FaableQL query"
33531
+ },
33532
+ {
33533
+ "schema": {
33534
+ "type": "string",
33535
+ "minLength": 1,
33536
+ "maxLength": 200
33537
+ },
33538
+ "in": "query",
33539
+ "name": "q",
33540
+ "required": false,
33541
+ "description": "Full-text search across: `name`, `slug`."
33542
+ }
33543
+ ],
33544
+ "security": [
33545
+ {
33546
+ "bearerAuth": []
33547
+ }
33548
+ ],
33549
+ "responses": {
33550
+ "200": {
33551
+ "description": "Default Response",
33552
+ "content": {
33553
+ "application/json": {
33554
+ "schema": {
33555
+ "type": "object",
33556
+ "required": [
33557
+ "next",
33558
+ "results"
33559
+ ],
33560
+ "properties": {
33561
+ "next": {
33562
+ "anyOf": [
33563
+ {
33564
+ "type": "string"
33565
+ },
33566
+ {
33567
+ "type": "null"
33568
+ }
33569
+ ]
33570
+ },
33571
+ "results": {
33572
+ "type": "array",
33573
+ "items": {
33574
+ "$ref": "#/components/schemas/Team"
33575
+ }
33576
+ }
33577
+ },
33578
+ "additionalProperties": false
33579
+ }
33580
+ }
33581
+ }
33582
+ },
33583
+ "400": {
33584
+ "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.",
33585
+ "content": {
33586
+ "application/json": {
33587
+ "schema": {
33588
+ "allOf": [
33589
+ {
33590
+ "$ref": "#/components/schemas/ErrorResponse"
33591
+ },
33592
+ {
33593
+ "type": "object",
33594
+ "properties": {
33595
+ "error_code": {
33596
+ "type": "string",
33597
+ "enum": [
33598
+ "invalid_query",
33599
+ "invalid_expand",
33600
+ "search_not_supported",
33601
+ "validation_error"
33602
+ ]
33603
+ }
33604
+ }
33605
+ }
33606
+ ]
33607
+ }
33608
+ }
33609
+ }
33610
+ },
33611
+ "401": {
33612
+ "description": "`unauthorized` — The request carries no valid credentials.",
33613
+ "content": {
33614
+ "application/json": {
33615
+ "schema": {
33616
+ "allOf": [
33617
+ {
33618
+ "$ref": "#/components/schemas/ErrorResponse"
33619
+ },
33620
+ {
33621
+ "type": "object",
33622
+ "properties": {
33623
+ "error_code": {
33624
+ "type": "string",
33625
+ "enum": [
33626
+ "unauthorized"
33627
+ ]
33628
+ }
33629
+ }
33630
+ }
33631
+ ]
33632
+ }
33633
+ }
33634
+ }
33635
+ },
33636
+ "403": {
33637
+ "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.",
33638
+ "content": {
33639
+ "application/json": {
33640
+ "schema": {
33641
+ "allOf": [
33642
+ {
33643
+ "$ref": "#/components/schemas/ErrorResponse"
33644
+ },
33645
+ {
33646
+ "type": "object",
33647
+ "properties": {
33648
+ "error_code": {
33649
+ "type": "string",
33650
+ "enum": [
33651
+ "forbidden",
33652
+ "insufficient_scope",
33653
+ "user_suspended"
33654
+ ]
33655
+ }
33656
+ }
33657
+ }
33658
+ ]
33659
+ }
33660
+ }
33661
+ }
33662
+ },
33663
+ "404": {
33664
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
33665
+ "content": {
33666
+ "application/json": {
33667
+ "schema": {
33668
+ "allOf": [
33669
+ {
33670
+ "$ref": "#/components/schemas/ErrorResponse"
33671
+ },
33672
+ {
33673
+ "type": "object",
33674
+ "properties": {
33675
+ "error_code": {
33676
+ "type": "string",
33677
+ "enum": [
33678
+ "account_not_found"
33679
+ ]
33680
+ }
33681
+ }
33682
+ }
33683
+ ]
33684
+ }
33685
+ }
33686
+ }
33687
+ },
33688
+ "429": {
33689
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
33690
+ "content": {
33691
+ "application/json": {
33692
+ "schema": {
33693
+ "allOf": [
33694
+ {
33695
+ "$ref": "#/components/schemas/ErrorResponse"
33696
+ },
33697
+ {
33698
+ "type": "object",
33699
+ "properties": {
33700
+ "error_code": {
33701
+ "type": "string",
33702
+ "enum": [
33703
+ "too_many_requests"
33704
+ ]
33705
+ }
33706
+ }
33707
+ }
33708
+ ]
33709
+ }
33710
+ }
33711
+ }
33712
+ },
33713
+ "500": {
33714
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
33715
+ "content": {
33716
+ "application/json": {
33717
+ "schema": {
33718
+ "allOf": [
33719
+ {
33720
+ "$ref": "#/components/schemas/ErrorResponse"
33721
+ },
33722
+ {
33723
+ "type": "object",
33724
+ "properties": {
33725
+ "error_code": {
33726
+ "type": "string",
33727
+ "enum": [
33728
+ "internal_error"
33729
+ ]
33730
+ }
33731
+ }
33732
+ }
33733
+ ]
33734
+ }
33735
+ }
33736
+ }
33737
+ }
33738
+ }
33739
+ },
33740
+ "post": {
33741
+ "operationId": "team/create",
33742
+ "summary": "Create Team",
33743
+ "tags": [
33744
+ "team"
33745
+ ],
33746
+ "description": "Create Team",
33747
+ "requestBody": {
33748
+ "required": true,
33749
+ "content": {
33750
+ "application/json": {
33751
+ "schema": {
33752
+ "type": "object",
33753
+ "required": [
33754
+ "name"
33755
+ ],
33756
+ "properties": {
33757
+ "name": {
33758
+ "type": "string",
33759
+ "description": "Human-readable name of the team.",
33760
+ "example": "Acme Engineering"
33761
+ },
33762
+ "description": {
33763
+ "type": "string",
33764
+ "description": "Optional free-form description of the team."
33765
+ },
33766
+ "metadata": {
33767
+ "type": "object",
33768
+ "properties": {},
33769
+ "additionalProperties": true,
33770
+ "description": "Add Metadata"
33771
+ }
33772
+ },
33773
+ "description": "TeamCreate",
33774
+ "additionalProperties": false
33775
+ }
33776
+ }
33777
+ },
33778
+ "description": "TeamCreate"
33779
+ },
33780
+ "security": [
33781
+ {
33782
+ "bearerAuth": []
33783
+ }
33784
+ ],
33785
+ "responses": {
33786
+ "200": {
33787
+ "description": "Team",
33788
+ "content": {
33789
+ "application/json": {
33790
+ "schema": {
33791
+ "type": "object",
33792
+ "required": [
33793
+ "id",
33794
+ "name",
33795
+ "slug",
33796
+ "description",
33797
+ "logo_url",
33798
+ "account",
33799
+ "createdAt"
33800
+ ],
33801
+ "properties": {
33802
+ "id": {
33803
+ "type": "string",
33804
+ "description": "Team ID"
33805
+ },
33806
+ "name": {
33807
+ "type": "string",
33808
+ "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
33809
+ "example": "Acme Engineering"
33810
+ },
33811
+ "slug": {
33812
+ "type": "string",
33813
+ "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
33814
+ "example": "acme-engineering"
33815
+ },
33816
+ "description": {
33817
+ "type": "string",
33818
+ "description": "Optional free-form description of the team.",
33819
+ "nullable": true
33820
+ },
33821
+ "logo_url": {
33822
+ "type": "string",
33823
+ "description": "Optional URL of an image used as the team avatar/logo.",
33824
+ "nullable": true
33825
+ },
33826
+ "organization": {
33827
+ "type": "string",
33828
+ "description": "Id of the Organization the team belongs to, or `null`. Changed only with `PUT /team/{team_id}/organization`.",
33829
+ "nullable": true
33830
+ },
33831
+ "account": {
33832
+ "type": "string",
33833
+ "description": "Object is related with this account"
33834
+ },
33835
+ "metadata": {
33836
+ "type": "object",
33837
+ "properties": {},
33838
+ "additionalProperties": true,
33839
+ "description": "TeamMetadata",
33840
+ "default": {}
33841
+ },
33842
+ "createdAt": {
33843
+ "type": "string",
33844
+ "description": "Team creation date"
33845
+ },
33846
+ "updatedAt": {
33847
+ "type": "string",
33848
+ "description": "Team updated date"
33849
+ }
33850
+ },
33851
+ "description": "Team"
33852
+ }
33853
+ }
33854
+ }
33855
+ },
33856
+ "400": {
33857
+ "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.",
33858
+ "content": {
33859
+ "application/json": {
33860
+ "schema": {
33861
+ "allOf": [
33862
+ {
33863
+ "$ref": "#/components/schemas/ErrorResponse"
33864
+ },
33865
+ {
33866
+ "type": "object",
33867
+ "properties": {
33868
+ "error_code": {
33869
+ "type": "string",
33870
+ "enum": [
33871
+ "already_exists",
33872
+ "validation_error"
33873
+ ]
33874
+ }
33875
+ }
33876
+ }
33877
+ ]
33878
+ }
33879
+ }
33880
+ }
33881
+ },
33882
+ "401": {
33883
+ "description": "`unauthorized` — The request carries no valid credentials.",
33884
+ "content": {
33885
+ "application/json": {
33886
+ "schema": {
33887
+ "allOf": [
33888
+ {
33889
+ "$ref": "#/components/schemas/ErrorResponse"
33890
+ },
33891
+ {
33892
+ "type": "object",
33893
+ "properties": {
33894
+ "error_code": {
33895
+ "type": "string",
33896
+ "enum": [
33897
+ "unauthorized"
33898
+ ]
33899
+ }
33900
+ }
33901
+ }
33902
+ ]
33903
+ }
33904
+ }
33905
+ }
33906
+ },
33907
+ "403": {
33908
+ "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.",
33909
+ "content": {
33910
+ "application/json": {
33911
+ "schema": {
33912
+ "allOf": [
33913
+ {
33914
+ "$ref": "#/components/schemas/ErrorResponse"
33915
+ },
33916
+ {
33917
+ "type": "object",
33918
+ "properties": {
33919
+ "error_code": {
33920
+ "type": "string",
33921
+ "enum": [
33922
+ "forbidden",
33923
+ "insufficient_scope",
33924
+ "user_suspended"
33925
+ ]
33926
+ }
33927
+ }
33928
+ }
33929
+ ]
33930
+ }
33931
+ }
33932
+ }
33933
+ },
33934
+ "404": {
33935
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
33936
+ "content": {
33937
+ "application/json": {
33938
+ "schema": {
33939
+ "allOf": [
33940
+ {
33941
+ "$ref": "#/components/schemas/ErrorResponse"
33942
+ },
33943
+ {
33944
+ "type": "object",
33945
+ "properties": {
33946
+ "error_code": {
33947
+ "type": "string",
33948
+ "enum": [
33949
+ "account_not_found"
33950
+ ]
33951
+ }
33952
+ }
33953
+ }
33954
+ ]
33955
+ }
33956
+ }
33957
+ }
33958
+ },
33959
+ "429": {
33960
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
33961
+ "content": {
33962
+ "application/json": {
33963
+ "schema": {
33964
+ "allOf": [
33965
+ {
33966
+ "$ref": "#/components/schemas/ErrorResponse"
33967
+ },
33968
+ {
33969
+ "type": "object",
33970
+ "properties": {
33971
+ "error_code": {
33972
+ "type": "string",
33973
+ "enum": [
33974
+ "too_many_requests"
33975
+ ]
33976
+ }
33977
+ }
33978
+ }
33979
+ ]
33980
+ }
33981
+ }
33982
+ }
33983
+ },
33984
+ "500": {
33985
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
33986
+ "content": {
33987
+ "application/json": {
33988
+ "schema": {
33989
+ "allOf": [
33990
+ {
33991
+ "$ref": "#/components/schemas/ErrorResponse"
33992
+ },
33993
+ {
33994
+ "type": "object",
33995
+ "properties": {
33996
+ "error_code": {
33997
+ "type": "string",
33998
+ "enum": [
33999
+ "internal_error"
34000
+ ]
34001
+ }
34002
+ }
34003
+ }
34004
+ ]
34005
+ }
34006
+ }
34007
+ }
34008
+ }
34009
+ }
34010
+ }
34011
+ },
34012
+ "/team/{team_id}": {
34013
+ "get": {
34014
+ "operationId": "team/get",
34015
+ "summary": "Get Team",
34016
+ "tags": [
34017
+ "team"
34018
+ ],
34019
+ "description": "Get Team",
34020
+ "parameters": [
34021
+ {
34022
+ "schema": {
34023
+ "type": "string"
34024
+ },
34025
+ "in": "path",
34026
+ "name": "team_id",
34027
+ "required": true
34028
+ }
34029
+ ],
34030
+ "security": [
34031
+ {
34032
+ "bearerAuth": []
34033
+ }
34034
+ ],
34035
+ "responses": {
34036
+ "200": {
34037
+ "description": "Team",
34038
+ "content": {
34039
+ "application/json": {
34040
+ "schema": {
34041
+ "type": "object",
34042
+ "required": [
34043
+ "id",
34044
+ "name",
34045
+ "slug",
34046
+ "description",
34047
+ "logo_url",
34048
+ "account",
34049
+ "createdAt"
34050
+ ],
34051
+ "properties": {
34052
+ "id": {
34053
+ "type": "string",
34054
+ "description": "Team ID"
34055
+ },
34056
+ "name": {
34057
+ "type": "string",
34058
+ "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34059
+ "example": "Acme Engineering"
34060
+ },
34061
+ "slug": {
34062
+ "type": "string",
34063
+ "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34064
+ "example": "acme-engineering"
34065
+ },
34066
+ "description": {
34067
+ "type": "string",
34068
+ "description": "Optional free-form description of the team.",
34069
+ "nullable": true
34070
+ },
34071
+ "logo_url": {
34072
+ "type": "string",
34073
+ "description": "Optional URL of an image used as the team avatar/logo.",
34074
+ "nullable": true
34075
+ },
34076
+ "organization": {
34077
+ "type": "string",
34078
+ "description": "Id of the Organization the team belongs to, or `null`. Changed only with `PUT /team/{team_id}/organization`.",
34079
+ "nullable": true
34080
+ },
34081
+ "account": {
34082
+ "type": "string",
34083
+ "description": "Object is related with this account"
34084
+ },
34085
+ "metadata": {
34086
+ "type": "object",
34087
+ "properties": {},
34088
+ "additionalProperties": true,
34089
+ "description": "TeamMetadata",
34090
+ "default": {}
34091
+ },
34092
+ "createdAt": {
34093
+ "type": "string",
34094
+ "description": "Team creation date"
34095
+ },
34096
+ "updatedAt": {
34097
+ "type": "string",
34098
+ "description": "Team updated date"
34099
+ }
34100
+ },
34101
+ "description": "Team"
34102
+ }
34103
+ }
34104
+ }
34105
+ },
34106
+ "400": {
34107
+ "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.",
34108
+ "content": {
34109
+ "application/json": {
34110
+ "schema": {
34111
+ "allOf": [
34112
+ {
34113
+ "$ref": "#/components/schemas/ErrorResponse"
34114
+ },
34115
+ {
34116
+ "type": "object",
34117
+ "properties": {
34118
+ "error_code": {
34119
+ "type": "string",
34120
+ "enum": [
34121
+ "invalid_id",
34122
+ "invalid_expand",
34123
+ "validation_error"
34124
+ ]
34125
+ }
34126
+ }
34127
+ }
34128
+ ]
34129
+ }
34130
+ }
34131
+ }
34132
+ },
34133
+ "401": {
34134
+ "description": "`unauthorized` — The request carries no valid credentials.",
34135
+ "content": {
34136
+ "application/json": {
34137
+ "schema": {
34138
+ "allOf": [
34139
+ {
34140
+ "$ref": "#/components/schemas/ErrorResponse"
34141
+ },
34142
+ {
34143
+ "type": "object",
34144
+ "properties": {
34145
+ "error_code": {
34146
+ "type": "string",
34147
+ "enum": [
34148
+ "unauthorized"
34149
+ ]
34150
+ }
34151
+ }
34152
+ }
34153
+ ]
34154
+ }
34155
+ }
34156
+ }
34157
+ },
34158
+ "403": {
34159
+ "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.",
34160
+ "content": {
34161
+ "application/json": {
34162
+ "schema": {
34163
+ "allOf": [
34164
+ {
34165
+ "$ref": "#/components/schemas/ErrorResponse"
34166
+ },
34167
+ {
34168
+ "type": "object",
34169
+ "properties": {
34170
+ "error_code": {
34171
+ "type": "string",
34172
+ "enum": [
34173
+ "forbidden",
34174
+ "insufficient_scope",
34175
+ "user_suspended"
34176
+ ]
34177
+ }
34178
+ }
34179
+ }
34180
+ ]
34181
+ }
34182
+ }
34183
+ }
34184
+ },
34185
+ "404": {
34186
+ "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).",
34187
+ "content": {
34188
+ "application/json": {
34189
+ "schema": {
34190
+ "allOf": [
34191
+ {
34192
+ "$ref": "#/components/schemas/ErrorResponse"
34193
+ },
34194
+ {
34195
+ "type": "object",
34196
+ "properties": {
34197
+ "error_code": {
34198
+ "type": "string",
34199
+ "enum": [
34200
+ "not_found",
34201
+ "account_not_found"
34202
+ ]
34203
+ }
34204
+ }
34205
+ }
34206
+ ]
34207
+ }
34208
+ }
34209
+ }
34210
+ },
34211
+ "429": {
34212
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
34213
+ "content": {
34214
+ "application/json": {
34215
+ "schema": {
34216
+ "allOf": [
34217
+ {
34218
+ "$ref": "#/components/schemas/ErrorResponse"
34219
+ },
34220
+ {
34221
+ "type": "object",
34222
+ "properties": {
34223
+ "error_code": {
34224
+ "type": "string",
34225
+ "enum": [
34226
+ "too_many_requests"
34227
+ ]
34228
+ }
34229
+ }
34230
+ }
34231
+ ]
34232
+ }
34233
+ }
34234
+ }
34235
+ },
34236
+ "500": {
34237
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
34238
+ "content": {
34239
+ "application/json": {
34240
+ "schema": {
34241
+ "allOf": [
34242
+ {
34243
+ "$ref": "#/components/schemas/ErrorResponse"
34244
+ },
34245
+ {
34246
+ "type": "object",
34247
+ "properties": {
34248
+ "error_code": {
34249
+ "type": "string",
34250
+ "enum": [
34251
+ "internal_error"
34252
+ ]
34253
+ }
34254
+ }
34255
+ }
34256
+ ]
34257
+ }
34258
+ }
34259
+ }
34260
+ }
34261
+ }
34262
+ },
34263
+ "post": {
34264
+ "operationId": "team/update",
34265
+ "summary": "Update Team",
34266
+ "tags": [
34267
+ "team"
34268
+ ],
34269
+ "description": "Update Team",
34270
+ "requestBody": {
34271
+ "required": true,
34272
+ "content": {
34273
+ "application/json": {
34274
+ "schema": {
34275
+ "type": "object",
34276
+ "properties": {
34277
+ "name": {
34278
+ "type": "string",
34279
+ "description": "New human-readable name for the team."
34280
+ },
34281
+ "description": {
34282
+ "type": "string",
34283
+ "description": "New free-form description for the team."
34284
+ },
34285
+ "metadata": {
34286
+ "type": "object",
34287
+ "properties": {},
34288
+ "additionalProperties": true,
34289
+ "description": "Arbitrary key/value pairs attached to the team. Replaces the previous metadata entirely."
34290
+ }
34291
+ },
34292
+ "description": "Partial update for a Team. Only the supplied fields are modified. `slug` is auto-derived from `name` and is not user-editable.",
34293
+ "additionalProperties": false
34294
+ }
34295
+ }
34296
+ },
34297
+ "description": "Partial update for a Team. Only the supplied fields are modified. `slug` is auto-derived from `name` and is not user-editable."
34298
+ },
34299
+ "parameters": [
34300
+ {
34301
+ "schema": {
34302
+ "type": "string"
34303
+ },
34304
+ "in": "path",
34305
+ "name": "team_id",
34306
+ "required": true
34307
+ }
34308
+ ],
34309
+ "security": [
34310
+ {
34311
+ "bearerAuth": []
34312
+ }
34313
+ ],
34314
+ "responses": {
34315
+ "200": {
34316
+ "description": "Team",
34317
+ "content": {
34318
+ "application/json": {
34319
+ "schema": {
34320
+ "type": "object",
34321
+ "required": [
34322
+ "id",
34323
+ "name",
34324
+ "slug",
34325
+ "description",
34326
+ "logo_url",
34327
+ "account",
34328
+ "createdAt"
34329
+ ],
34330
+ "properties": {
34331
+ "id": {
34332
+ "type": "string",
34333
+ "description": "Team ID"
34334
+ },
34335
+ "name": {
34336
+ "type": "string",
34337
+ "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34338
+ "example": "Acme Engineering"
34339
+ },
34340
+ "slug": {
34341
+ "type": "string",
34342
+ "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34343
+ "example": "acme-engineering"
34344
+ },
34345
+ "description": {
34346
+ "type": "string",
34347
+ "description": "Optional free-form description of the team.",
34348
+ "nullable": true
34349
+ },
34350
+ "logo_url": {
34351
+ "type": "string",
34352
+ "description": "Optional URL of an image used as the team avatar/logo.",
34353
+ "nullable": true
34354
+ },
34355
+ "organization": {
34356
+ "type": "string",
34357
+ "description": "Id of the Organization the team belongs to, or `null`. Changed only with `PUT /team/{team_id}/organization`.",
34358
+ "nullable": true
34359
+ },
34360
+ "account": {
34361
+ "type": "string",
34362
+ "description": "Object is related with this account"
34363
+ },
34364
+ "metadata": {
34365
+ "type": "object",
34366
+ "properties": {},
34367
+ "additionalProperties": true,
34368
+ "description": "TeamMetadata",
34369
+ "default": {}
34370
+ },
34371
+ "createdAt": {
34372
+ "type": "string",
34373
+ "description": "Team creation date"
34374
+ },
34375
+ "updatedAt": {
34376
+ "type": "string",
34377
+ "description": "Team updated date"
34378
+ }
34379
+ },
34380
+ "description": "Team"
34381
+ }
34382
+ }
34383
+ }
34384
+ },
34385
+ "400": {
34386
+ "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.",
34387
+ "content": {
34388
+ "application/json": {
34389
+ "schema": {
34390
+ "allOf": [
34391
+ {
34392
+ "$ref": "#/components/schemas/ErrorResponse"
34393
+ },
34394
+ {
34395
+ "type": "object",
34396
+ "properties": {
34397
+ "error_code": {
34398
+ "type": "string",
34399
+ "enum": [
34400
+ "invalid_id",
34401
+ "already_exists",
34402
+ "validation_error"
34403
+ ]
34404
+ }
34405
+ }
34406
+ }
34407
+ ]
34408
+ }
34409
+ }
34410
+ }
34411
+ },
34412
+ "401": {
34413
+ "description": "`unauthorized` — The request carries no valid credentials.",
34414
+ "content": {
34415
+ "application/json": {
34416
+ "schema": {
34417
+ "allOf": [
34418
+ {
34419
+ "$ref": "#/components/schemas/ErrorResponse"
34420
+ },
34421
+ {
34422
+ "type": "object",
34423
+ "properties": {
34424
+ "error_code": {
34425
+ "type": "string",
34426
+ "enum": [
34427
+ "unauthorized"
34428
+ ]
34429
+ }
34430
+ }
34431
+ }
34432
+ ]
34433
+ }
34434
+ }
34435
+ }
34436
+ },
34437
+ "403": {
34438
+ "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.",
34439
+ "content": {
34440
+ "application/json": {
34441
+ "schema": {
34442
+ "allOf": [
34443
+ {
34444
+ "$ref": "#/components/schemas/ErrorResponse"
34445
+ },
34446
+ {
34447
+ "type": "object",
34448
+ "properties": {
34449
+ "error_code": {
34450
+ "type": "string",
34451
+ "enum": [
34452
+ "forbidden",
34453
+ "insufficient_scope",
34454
+ "user_suspended"
34455
+ ]
34456
+ }
34457
+ }
34458
+ }
34459
+ ]
34460
+ }
34461
+ }
34462
+ }
34463
+ },
34464
+ "404": {
34465
+ "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).",
34466
+ "content": {
34467
+ "application/json": {
34468
+ "schema": {
34469
+ "allOf": [
34470
+ {
34471
+ "$ref": "#/components/schemas/ErrorResponse"
34472
+ },
34473
+ {
34474
+ "type": "object",
34475
+ "properties": {
34476
+ "error_code": {
34477
+ "type": "string",
34478
+ "enum": [
34479
+ "not_found",
34480
+ "account_not_found"
34481
+ ]
34482
+ }
34483
+ }
34484
+ }
34485
+ ]
34486
+ }
34487
+ }
34488
+ }
34489
+ },
34490
+ "429": {
34491
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
34492
+ "content": {
34493
+ "application/json": {
34494
+ "schema": {
34495
+ "allOf": [
34496
+ {
34497
+ "$ref": "#/components/schemas/ErrorResponse"
34498
+ },
34499
+ {
34500
+ "type": "object",
34501
+ "properties": {
34502
+ "error_code": {
34503
+ "type": "string",
34504
+ "enum": [
34505
+ "too_many_requests"
34506
+ ]
34507
+ }
34508
+ }
34509
+ }
34510
+ ]
34511
+ }
34512
+ }
34513
+ }
34514
+ },
34515
+ "500": {
34516
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
34517
+ "content": {
34518
+ "application/json": {
34519
+ "schema": {
34520
+ "allOf": [
34521
+ {
34522
+ "$ref": "#/components/schemas/ErrorResponse"
34523
+ },
34524
+ {
34525
+ "type": "object",
34526
+ "properties": {
34527
+ "error_code": {
34528
+ "type": "string",
34529
+ "enum": [
34530
+ "internal_error"
34531
+ ]
34532
+ }
34533
+ }
34534
+ }
34535
+ ]
34536
+ }
34537
+ }
34538
+ }
34539
+ }
34540
+ }
34541
+ },
34542
+ "delete": {
34543
+ "operationId": "team/delete",
34544
+ "summary": "Delete Team",
34545
+ "tags": [
34546
+ "team"
34547
+ ],
34548
+ "description": "Delete Team",
34549
+ "parameters": [
34550
+ {
34551
+ "schema": {
34552
+ "type": "string"
34553
+ },
34554
+ "in": "path",
34555
+ "name": "team_id",
34556
+ "required": true
34557
+ }
34558
+ ],
34559
+ "security": [
34560
+ {
34561
+ "bearerAuth": []
34562
+ }
34563
+ ],
34564
+ "responses": {
34565
+ "200": {
34566
+ "description": "Team",
34567
+ "content": {
34568
+ "application/json": {
34569
+ "schema": {
34570
+ "type": "object",
34571
+ "required": [
34572
+ "id",
34573
+ "name",
34574
+ "slug",
34575
+ "description",
34576
+ "logo_url",
34577
+ "account",
34578
+ "createdAt"
34579
+ ],
34580
+ "properties": {
34581
+ "id": {
34582
+ "type": "string",
34583
+ "description": "Team ID"
34584
+ },
34585
+ "name": {
34586
+ "type": "string",
34587
+ "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34588
+ "example": "Acme Engineering"
34589
+ },
34590
+ "slug": {
34591
+ "type": "string",
34592
+ "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34593
+ "example": "acme-engineering"
34594
+ },
34595
+ "description": {
34596
+ "type": "string",
34597
+ "description": "Optional free-form description of the team.",
34598
+ "nullable": true
34599
+ },
34600
+ "logo_url": {
34601
+ "type": "string",
34602
+ "description": "Optional URL of an image used as the team avatar/logo.",
34603
+ "nullable": true
34604
+ },
34605
+ "organization": {
34606
+ "type": "string",
34607
+ "description": "Id of the Organization the team belongs to, or `null`. Changed only with `PUT /team/{team_id}/organization`.",
34608
+ "nullable": true
34609
+ },
34610
+ "account": {
34611
+ "type": "string",
34612
+ "description": "Object is related with this account"
34613
+ },
34614
+ "metadata": {
34615
+ "type": "object",
34616
+ "properties": {},
34617
+ "additionalProperties": true,
34618
+ "description": "TeamMetadata",
34619
+ "default": {}
34620
+ },
34621
+ "createdAt": {
34622
+ "type": "string",
34623
+ "description": "Team creation date"
34624
+ },
34625
+ "updatedAt": {
34626
+ "type": "string",
34627
+ "description": "Team updated date"
34628
+ }
34629
+ },
34630
+ "description": "Team"
34631
+ }
34632
+ }
34633
+ }
34634
+ },
34635
+ "400": {
34636
+ "description": "`invalid_id` — The id in the path is not a valid id for this resource.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
34637
+ "content": {
34638
+ "application/json": {
34639
+ "schema": {
34640
+ "allOf": [
34641
+ {
34642
+ "$ref": "#/components/schemas/ErrorResponse"
34643
+ },
34644
+ {
34645
+ "type": "object",
34646
+ "properties": {
34647
+ "error_code": {
34648
+ "type": "string",
34649
+ "enum": [
34650
+ "invalid_id",
34651
+ "validation_error"
34652
+ ]
34653
+ }
34654
+ }
34655
+ }
34656
+ ]
34657
+ }
34658
+ }
34659
+ }
34660
+ },
34661
+ "401": {
34662
+ "description": "`unauthorized` — The request carries no valid credentials.",
34663
+ "content": {
34664
+ "application/json": {
34665
+ "schema": {
34666
+ "allOf": [
34667
+ {
34668
+ "$ref": "#/components/schemas/ErrorResponse"
34669
+ },
34670
+ {
34671
+ "type": "object",
34672
+ "properties": {
34673
+ "error_code": {
34674
+ "type": "string",
34675
+ "enum": [
34676
+ "unauthorized"
34677
+ ]
34678
+ }
34679
+ }
34680
+ }
34681
+ ]
34682
+ }
34683
+ }
34684
+ }
34685
+ },
34686
+ "403": {
34687
+ "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.",
34688
+ "content": {
34689
+ "application/json": {
34690
+ "schema": {
34691
+ "allOf": [
34692
+ {
34693
+ "$ref": "#/components/schemas/ErrorResponse"
34694
+ },
34695
+ {
34696
+ "type": "object",
34697
+ "properties": {
34698
+ "error_code": {
34699
+ "type": "string",
34700
+ "enum": [
34701
+ "forbidden",
34702
+ "insufficient_scope",
34703
+ "user_suspended"
34704
+ ]
34705
+ }
34706
+ }
34707
+ }
34708
+ ]
34709
+ }
34710
+ }
34711
+ }
34712
+ },
34713
+ "404": {
34714
+ "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).",
34715
+ "content": {
34716
+ "application/json": {
34717
+ "schema": {
34718
+ "allOf": [
34719
+ {
34720
+ "$ref": "#/components/schemas/ErrorResponse"
34721
+ },
34722
+ {
34723
+ "type": "object",
34724
+ "properties": {
34725
+ "error_code": {
34726
+ "type": "string",
34727
+ "enum": [
34728
+ "not_found",
34729
+ "account_not_found"
34730
+ ]
34731
+ }
34732
+ }
34733
+ }
34734
+ ]
34735
+ }
34736
+ }
34737
+ }
34738
+ },
34739
+ "429": {
34740
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
34741
+ "content": {
34742
+ "application/json": {
34743
+ "schema": {
34744
+ "allOf": [
34745
+ {
34746
+ "$ref": "#/components/schemas/ErrorResponse"
34747
+ },
34748
+ {
34749
+ "type": "object",
34750
+ "properties": {
34751
+ "error_code": {
34752
+ "type": "string",
34753
+ "enum": [
34754
+ "too_many_requests"
34755
+ ]
34756
+ }
34757
+ }
34758
+ }
34759
+ ]
34760
+ }
34761
+ }
34762
+ }
34763
+ },
34764
+ "500": {
34765
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
34766
+ "content": {
34767
+ "application/json": {
34768
+ "schema": {
34769
+ "allOf": [
34770
+ {
34771
+ "$ref": "#/components/schemas/ErrorResponse"
34772
+ },
34773
+ {
34774
+ "type": "object",
34775
+ "properties": {
34776
+ "error_code": {
34777
+ "type": "string",
34778
+ "enum": [
34779
+ "internal_error"
34780
+ ]
34781
+ }
34782
+ }
34783
+ }
34784
+ ]
34785
+ }
34786
+ }
34787
+ }
34788
+ }
34789
+ }
34790
+ },
34791
+ "put": {
34792
+ "operationId": "team/put",
34793
+ "summary": "Create or update a Team with a given id",
34794
+ "tags": [
34795
+ "team"
34796
+ ],
34797
+ "description": "Creates the Team with the given id if it does not exist in this tenant (201), or updates its name, description, metadata and — when given — slug (200). Idempotent. Needs both `create:teams` and `update:teams`. `team_id_unavailable` (409) when the id cannot be used in this tenant; `already_exists` when the slug is taken by another team.",
34798
+ "requestBody": {
34799
+ "required": true,
34800
+ "content": {
34801
+ "application/json": {
34802
+ "schema": {
34803
+ "type": "object",
34804
+ "required": [
34805
+ "name"
34806
+ ],
34807
+ "properties": {
34808
+ "name": {
34809
+ "type": "string",
34810
+ "minLength": 1,
34811
+ "description": "Human-readable name of the team.",
34812
+ "example": "Acme Engineering"
34813
+ },
34814
+ "slug": {
34815
+ "type": "string",
34816
+ "minLength": 1,
34817
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
34818
+ "description": "URL-safe identifier, unique within the tenant. Derived from `name` when omitted on creation; when given, it is set as-is (also on update). Pass it when names can repeat.",
34819
+ "example": "acme-engineering"
34820
+ },
34821
+ "description": {
34822
+ "type": "string",
34823
+ "description": "Optional free-form description."
34824
+ },
34825
+ "metadata": {
34826
+ "type": "object",
34827
+ "properties": {},
34828
+ "additionalProperties": true,
34829
+ "description": "Arbitrary key/value pairs attached to the team. Replaces the previous metadata entirely."
34830
+ }
34831
+ },
34832
+ "additionalProperties": false,
34833
+ "description": "Payload for creating or updating a Team under a caller-chosen id."
34834
+ }
34835
+ }
34836
+ },
34837
+ "description": "Payload for creating or updating a Team under a caller-chosen id."
34838
+ },
34839
+ "parameters": [
34840
+ {
34841
+ "schema": {
34842
+ "type": "string",
34843
+ "pattern": "^team_[0-9a-f]{24}$"
34844
+ },
34845
+ "in": "path",
34846
+ "name": "team_id",
34847
+ "required": true,
34848
+ "description": "Id of the team to create or update: `team_` followed by 24 lowercase hex characters, chosen by the caller."
34849
+ }
34850
+ ],
34851
+ "security": [
34852
+ {
34853
+ "bearerAuth": []
34854
+ }
34855
+ ],
34856
+ "responses": {
34857
+ "200": {
34858
+ "description": "Team",
34859
+ "content": {
34860
+ "application/json": {
34861
+ "schema": {
34862
+ "type": "object",
34863
+ "required": [
34864
+ "id",
34865
+ "name",
34866
+ "slug",
34867
+ "description",
34868
+ "logo_url",
34869
+ "account",
34870
+ "createdAt"
34871
+ ],
34872
+ "properties": {
34873
+ "id": {
34874
+ "type": "string",
34875
+ "description": "Team ID"
34876
+ },
34877
+ "name": {
34878
+ "type": "string",
34879
+ "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34880
+ "example": "Acme Engineering"
34881
+ },
34882
+ "slug": {
34883
+ "type": "string",
34884
+ "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34885
+ "example": "acme-engineering"
34886
+ },
34887
+ "description": {
34888
+ "type": "string",
34889
+ "description": "Optional free-form description of the team.",
34890
+ "nullable": true
34891
+ },
34892
+ "logo_url": {
34893
+ "type": "string",
34894
+ "description": "Optional URL of an image used as the team avatar/logo.",
34895
+ "nullable": true
34896
+ },
34897
+ "organization": {
34898
+ "type": "string",
34899
+ "description": "Id of the Organization the team belongs to, or `null`. Changed only with `PUT /team/{team_id}/organization`.",
34900
+ "nullable": true
34901
+ },
34902
+ "account": {
34903
+ "type": "string",
34904
+ "description": "Object is related with this account"
34905
+ },
34906
+ "metadata": {
34907
+ "type": "object",
34908
+ "properties": {},
34909
+ "additionalProperties": true,
34910
+ "description": "TeamMetadata",
34911
+ "default": {}
34912
+ },
34913
+ "createdAt": {
34914
+ "type": "string",
34915
+ "description": "Team creation date"
34916
+ },
34917
+ "updatedAt": {
34918
+ "type": "string",
34919
+ "description": "Team updated date"
34920
+ }
34921
+ },
34922
+ "description": "Team"
34923
+ }
34924
+ }
34925
+ }
34926
+ },
34927
+ "201": {
34928
+ "description": "Team",
34929
+ "content": {
34930
+ "application/json": {
34931
+ "schema": {
34932
+ "type": "object",
34933
+ "required": [
34934
+ "id",
34935
+ "name",
34936
+ "slug",
34937
+ "description",
34938
+ "logo_url",
34939
+ "account",
34940
+ "createdAt"
34941
+ ],
34942
+ "properties": {
34943
+ "id": {
34944
+ "type": "string",
34945
+ "description": "Team ID"
34946
+ },
34947
+ "name": {
34948
+ "type": "string",
34949
+ "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34950
+ "example": "Acme Engineering"
34951
+ },
34952
+ "slug": {
34953
+ "type": "string",
34954
+ "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34955
+ "example": "acme-engineering"
34956
+ },
34957
+ "description": {
34958
+ "type": "string",
34959
+ "description": "Optional free-form description of the team.",
34960
+ "nullable": true
34961
+ },
34962
+ "logo_url": {
34963
+ "type": "string",
34964
+ "description": "Optional URL of an image used as the team avatar/logo.",
34965
+ "nullable": true
34966
+ },
34967
+ "organization": {
34968
+ "type": "string",
34969
+ "description": "Id of the Organization the team belongs to, or `null`. Changed only with `PUT /team/{team_id}/organization`.",
34970
+ "nullable": true
34971
+ },
34972
+ "account": {
34973
+ "type": "string",
34974
+ "description": "Object is related with this account"
34975
+ },
34976
+ "metadata": {
34977
+ "type": "object",
34978
+ "properties": {},
34979
+ "additionalProperties": true,
34980
+ "description": "TeamMetadata",
34981
+ "default": {}
34982
+ },
34983
+ "createdAt": {
34984
+ "type": "string",
34985
+ "description": "Team creation date"
34986
+ },
34987
+ "updatedAt": {
34988
+ "type": "string",
34989
+ "description": "Team updated date"
34990
+ }
34991
+ },
34992
+ "description": "Team"
34993
+ }
34994
+ }
34995
+ }
34996
+ },
34997
+ "400": {
34998
+ "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.",
34999
+ "content": {
35000
+ "application/json": {
35001
+ "schema": {
35002
+ "allOf": [
35003
+ {
35004
+ "$ref": "#/components/schemas/ErrorResponse"
35005
+ },
35006
+ {
35007
+ "type": "object",
35008
+ "properties": {
35009
+ "error_code": {
35010
+ "type": "string",
35011
+ "enum": [
35012
+ "already_exists",
35013
+ "validation_error"
35014
+ ]
35015
+ }
35016
+ }
35017
+ }
35018
+ ]
35019
+ }
35020
+ }
35021
+ }
35022
+ },
35023
+ "401": {
35024
+ "description": "`unauthorized` — The request carries no valid credentials.",
35025
+ "content": {
35026
+ "application/json": {
35027
+ "schema": {
35028
+ "allOf": [
35029
+ {
35030
+ "$ref": "#/components/schemas/ErrorResponse"
35031
+ },
35032
+ {
35033
+ "type": "object",
35034
+ "properties": {
35035
+ "error_code": {
35036
+ "type": "string",
35037
+ "enum": [
35038
+ "unauthorized"
35039
+ ]
35040
+ }
35041
+ }
35042
+ }
35043
+ ]
35044
+ }
35045
+ }
35046
+ }
35047
+ },
35048
+ "403": {
35049
+ "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.",
35050
+ "content": {
35051
+ "application/json": {
35052
+ "schema": {
35053
+ "allOf": [
35054
+ {
35055
+ "$ref": "#/components/schemas/ErrorResponse"
35056
+ },
35057
+ {
35058
+ "type": "object",
35059
+ "properties": {
35060
+ "error_code": {
35061
+ "type": "string",
35062
+ "enum": [
35063
+ "forbidden",
35064
+ "insufficient_scope",
35065
+ "user_suspended"
35066
+ ]
35067
+ }
35068
+ }
35069
+ }
35070
+ ]
35071
+ }
35072
+ }
35073
+ }
35074
+ },
35075
+ "404": {
35076
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
35077
+ "content": {
35078
+ "application/json": {
35079
+ "schema": {
35080
+ "allOf": [
35081
+ {
35082
+ "$ref": "#/components/schemas/ErrorResponse"
35083
+ },
35084
+ {
35085
+ "type": "object",
35086
+ "properties": {
35087
+ "error_code": {
35088
+ "type": "string",
35089
+ "enum": [
35090
+ "account_not_found"
35091
+ ]
35092
+ }
35093
+ }
35094
+ }
35095
+ ]
35096
+ }
35097
+ }
35098
+ }
35099
+ },
35100
+ "409": {
35101
+ "description": "`team_id_unavailable` — The team id cannot be used in this tenant. Pick another id or let the API generate one.",
35102
+ "content": {
35103
+ "application/json": {
35104
+ "schema": {
35105
+ "allOf": [
35106
+ {
35107
+ "$ref": "#/components/schemas/ErrorResponse"
35108
+ },
35109
+ {
35110
+ "type": "object",
35111
+ "properties": {
35112
+ "error_code": {
35113
+ "type": "string",
35114
+ "enum": [
35115
+ "team_id_unavailable"
35116
+ ]
35117
+ }
35118
+ }
35119
+ }
35120
+ ]
35121
+ }
35122
+ }
35123
+ }
35124
+ },
35125
+ "429": {
35126
+ "description": "`too_many_requests` — Rate limit exceeded. Honour the `Retry-After` header.",
35127
+ "content": {
35128
+ "application/json": {
35129
+ "schema": {
35130
+ "allOf": [
35131
+ {
35132
+ "$ref": "#/components/schemas/ErrorResponse"
35133
+ },
35134
+ {
35135
+ "type": "object",
35136
+ "properties": {
35137
+ "error_code": {
35138
+ "type": "string",
35139
+ "enum": [
35140
+ "too_many_requests"
35141
+ ]
35142
+ }
35143
+ }
35144
+ }
35145
+ ]
35146
+ }
35147
+ }
35148
+ }
35149
+ },
35150
+ "500": {
35151
+ "description": "`internal_error` — Unexpected server error. Retry later; the request id is logged.",
35152
+ "content": {
35153
+ "application/json": {
35154
+ "schema": {
35155
+ "allOf": [
35156
+ {
35157
+ "$ref": "#/components/schemas/ErrorResponse"
35158
+ },
35159
+ {
35160
+ "type": "object",
35161
+ "properties": {
35162
+ "error_code": {
35163
+ "type": "string",
35164
+ "enum": [
35165
+ "internal_error"
35166
+ ]
35167
+ }
35168
+ }
35169
+ }
35170
+ ]
35171
+ }
35172
+ }
35173
+ }
35174
+ }
35175
+ }
35176
+ }
35177
+ },
35178
+ "/team/{team_id}/organization": {
35179
+ "put": {
35180
+ "operationId": "team/setOrganization",
35181
+ "summary": "Put a Team in an Organization, or take it out",
32782
35182
  "tags": [
32783
- "rolemember"
35183
+ "team"
32784
35184
  ],
32785
- "description": "Get Rolemember",
32786
- "parameters": [
32787
- {
32788
- "schema": {
32789
- "type": "array",
32790
- "items": {
32791
- "type": "string",
32792
- "enum": [
32793
- "user",
32794
- "role"
35185
+ "description": "Sets the Organization the Team belongs to (`null` = none). A team is in at most one organization; setting another one moves it. Belonging to an organization grants nobody access to the team. Emits `team.updated`.",
35186
+ "requestBody": {
35187
+ "required": true,
35188
+ "content": {
35189
+ "application/json": {
35190
+ "schema": {
35191
+ "type": "object",
35192
+ "required": [
35193
+ "organization"
32795
35194
  ],
32796
- "description": "Allowed expand paths on `rolemember`: `user`, `role`."
32797
- },
32798
- "maxItems": 2
32799
- },
32800
- "in": "query",
32801
- "name": "expand",
32802
- "required": false,
32803
- "description": "Expand id-only fields in the response. Pass one path per entry (e.g. `?expand=user`)."
32804
- },
35195
+ "properties": {
35196
+ "organization": {
35197
+ "type": "string",
35198
+ "description": "Id of an Organization of this tenant, or `null` to take the team out of its organization.",
35199
+ "nullable": true
35200
+ }
35201
+ },
35202
+ "additionalProperties": false
35203
+ }
35204
+ }
35205
+ }
35206
+ },
35207
+ "parameters": [
32805
35208
  {
32806
35209
  "schema": {
32807
35210
  "type": "string"
32808
35211
  },
32809
35212
  "in": "path",
32810
- "name": "rolemember_id",
35213
+ "name": "team_id",
32811
35214
  "required": true
32812
35215
  }
32813
35216
  ],
@@ -32818,46 +35221,49 @@
32818
35221
  ],
32819
35222
  "responses": {
32820
35223
  "200": {
32821
- "description": "RoleMember",
35224
+ "description": "Team",
32822
35225
  "content": {
32823
35226
  "application/json": {
32824
35227
  "schema": {
32825
35228
  "type": "object",
32826
35229
  "required": [
32827
35230
  "id",
32828
- "role",
32829
- "user",
35231
+ "name",
35232
+ "slug",
35233
+ "description",
35234
+ "logo_url",
32830
35235
  "account",
32831
35236
  "createdAt"
32832
35237
  ],
32833
35238
  "properties": {
32834
35239
  "id": {
32835
35240
  "type": "string",
32836
- "description": "RoleMember ID"
35241
+ "description": "Team ID"
32837
35242
  },
32838
- "role": {
32839
- "anyOf": [
32840
- {
32841
- "$ref": "#/components/schemas/Role"
32842
- },
32843
- {
32844
- "type": "string"
32845
- },
32846
- {}
32847
- ],
32848
- "description": "Role granted to the user. Returned as an id by default; pass `?expand=role` to inline the full Role object."
35243
+ "name": {
35244
+ "type": "string",
35245
+ "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
35246
+ "example": "Acme Engineering"
32849
35247
  },
32850
- "user": {
32851
- "anyOf": [
32852
- {
32853
- "$ref": "#/components/schemas/User"
32854
- },
32855
- {
32856
- "type": "string"
32857
- },
32858
- {}
32859
- ],
32860
- "description": "User the role is granted to. Returned as an id by default; pass `?expand=user` to inline the full User object."
35248
+ "slug": {
35249
+ "type": "string",
35250
+ "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
35251
+ "example": "acme-engineering"
35252
+ },
35253
+ "description": {
35254
+ "type": "string",
35255
+ "description": "Optional free-form description of the team.",
35256
+ "nullable": true
35257
+ },
35258
+ "logo_url": {
35259
+ "type": "string",
35260
+ "description": "Optional URL of an image used as the team avatar/logo.",
35261
+ "nullable": true
35262
+ },
35263
+ "organization": {
35264
+ "type": "string",
35265
+ "description": "Id of the Organization the team belongs to, or `null`. Changed only with `PUT /team/{team_id}/organization`.",
35266
+ "nullable": true
32861
35267
  },
32862
35268
  "account": {
32863
35269
  "type": "string",
@@ -32867,25 +35273,25 @@
32867
35273
  "type": "object",
32868
35274
  "properties": {},
32869
35275
  "additionalProperties": true,
32870
- "description": "RoleMemberMetadata",
35276
+ "description": "TeamMetadata",
32871
35277
  "default": {}
32872
35278
  },
32873
35279
  "createdAt": {
32874
35280
  "type": "string",
32875
- "description": "RoleMember creation date"
35281
+ "description": "Team creation date"
32876
35282
  },
32877
35283
  "updatedAt": {
32878
35284
  "type": "string",
32879
- "description": "RoleMember updated date"
35285
+ "description": "Team updated date"
32880
35286
  }
32881
35287
  },
32882
- "description": "RoleMember"
35288
+ "description": "Team"
32883
35289
  }
32884
35290
  }
32885
35291
  }
32886
35292
  },
32887
35293
  "400": {
32888
- "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.",
35294
+ "description": "`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
32889
35295
  "content": {
32890
35296
  "application/json": {
32891
35297
  "schema": {
@@ -32899,8 +35305,6 @@
32899
35305
  "error_code": {
32900
35306
  "type": "string",
32901
35307
  "enum": [
32902
- "invalid_id",
32903
- "invalid_expand",
32904
35308
  "validation_error"
32905
35309
  ]
32906
35310
  }
@@ -32964,7 +35368,7 @@
32964
35368
  }
32965
35369
  },
32966
35370
  "404": {
32967
- "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).",
35371
+ "description": "`not_found` — The resource does not exist in this account.\n\n`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).",
32968
35372
  "content": {
32969
35373
  "application/json": {
32970
35374
  "schema": {
@@ -32979,6 +35383,7 @@
32979
35383
  "type": "string",
32980
35384
  "enum": [
32981
35385
  "not_found",
35386
+ "organization_not_found",
32982
35387
  "account_not_found"
32983
35388
  ]
32984
35389
  }
@@ -33040,22 +35445,65 @@
33040
35445
  }
33041
35446
  }
33042
35447
  }
33043
- },
33044
- "delete": {
33045
- "operationId": "rolemember/delete",
33046
- "summary": "Delete Rolemember",
35448
+ }
35449
+ },
35450
+ "/organization": {
35451
+ "get": {
35452
+ "operationId": "organization/list",
35453
+ "summary": "List Organizations",
33047
35454
  "tags": [
33048
- "rolemember"
35455
+ "organization"
33049
35456
  ],
33050
- "description": "Delete Rolemember",
35457
+ "description": "List Organizations",
33051
35458
  "parameters": [
35459
+ {
35460
+ "schema": {
35461
+ "type": "number",
35462
+ "minimum": 1,
35463
+ "maximum": 200
35464
+ },
35465
+ "in": "query",
35466
+ "name": "pageSize",
35467
+ "required": false,
35468
+ "description": "Number of items per page (max 200)"
35469
+ },
33052
35470
  {
33053
35471
  "schema": {
33054
35472
  "type": "string"
33055
35473
  },
33056
- "in": "path",
33057
- "name": "rolemember_id",
33058
- "required": true
35474
+ "in": "query",
35475
+ "name": "cursor",
35476
+ "required": false,
35477
+ "description": "Cursor for next page"
35478
+ },
35479
+ {
35480
+ "schema": {
35481
+ "type": "string"
35482
+ },
35483
+ "in": "query",
35484
+ "name": "next",
35485
+ "required": false,
35486
+ "description": "Cursor returned by the previous page"
35487
+ },
35488
+ {
35489
+ "schema": {
35490
+ "type": "string"
35491
+ },
35492
+ "in": "query",
35493
+ "name": "query",
35494
+ "required": false,
35495
+ "description": "Filter using a FaableQL query"
35496
+ },
35497
+ {
35498
+ "schema": {
35499
+ "type": "string",
35500
+ "minLength": 1,
35501
+ "maxLength": 200
35502
+ },
35503
+ "in": "query",
35504
+ "name": "q",
35505
+ "required": false,
35506
+ "description": "Full-text search across: `name`, `slug`."
33059
35507
  }
33060
35508
  ],
33061
35509
  "security": [
@@ -33065,74 +35513,40 @@
33065
35513
  ],
33066
35514
  "responses": {
33067
35515
  "200": {
33068
- "description": "RoleMember",
35516
+ "description": "Default Response",
33069
35517
  "content": {
33070
35518
  "application/json": {
33071
35519
  "schema": {
33072
35520
  "type": "object",
33073
35521
  "required": [
33074
- "id",
33075
- "role",
33076
- "user",
33077
- "account",
33078
- "createdAt"
35522
+ "next",
35523
+ "results"
33079
35524
  ],
33080
35525
  "properties": {
33081
- "id": {
33082
- "type": "string",
33083
- "description": "RoleMember ID"
33084
- },
33085
- "role": {
35526
+ "next": {
33086
35527
  "anyOf": [
33087
- {
33088
- "$ref": "#/components/schemas/Role"
33089
- },
33090
35528
  {
33091
35529
  "type": "string"
33092
35530
  },
33093
- {}
33094
- ],
33095
- "description": "Role granted to the user. Returned as an id by default; pass `?expand=role` to inline the full Role object."
33096
- },
33097
- "user": {
33098
- "anyOf": [
33099
35531
  {
33100
- "$ref": "#/components/schemas/User"
33101
- },
33102
- {
33103
- "type": "string"
33104
- },
33105
- {}
33106
- ],
33107
- "description": "User the role is granted to. Returned as an id by default; pass `?expand=user` to inline the full User object."
33108
- },
33109
- "account": {
33110
- "type": "string",
33111
- "description": "Object is related with this account"
33112
- },
33113
- "metadata": {
33114
- "type": "object",
33115
- "properties": {},
33116
- "additionalProperties": true,
33117
- "description": "RoleMemberMetadata",
33118
- "default": {}
33119
- },
33120
- "createdAt": {
33121
- "type": "string",
33122
- "description": "RoleMember creation date"
35532
+ "type": "null"
35533
+ }
35534
+ ]
33123
35535
  },
33124
- "updatedAt": {
33125
- "type": "string",
33126
- "description": "RoleMember updated date"
35536
+ "results": {
35537
+ "type": "array",
35538
+ "items": {
35539
+ "$ref": "#/components/schemas/Organization"
35540
+ }
33127
35541
  }
33128
35542
  },
33129
- "description": "RoleMember"
35543
+ "additionalProperties": false
33130
35544
  }
33131
35545
  }
33132
35546
  }
33133
35547
  },
33134
35548
  "400": {
33135
- "description": "`invalid_id` — The id in the path is not a valid id for this resource.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
35549
+ "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.",
33136
35550
  "content": {
33137
35551
  "application/json": {
33138
35552
  "schema": {
@@ -33146,7 +35560,9 @@
33146
35560
  "error_code": {
33147
35561
  "type": "string",
33148
35562
  "enum": [
33149
- "invalid_id",
35563
+ "invalid_query",
35564
+ "invalid_expand",
35565
+ "search_not_supported",
33150
35566
  "validation_error"
33151
35567
  ]
33152
35568
  }
@@ -33210,7 +35626,7 @@
33210
35626
  }
33211
35627
  },
33212
35628
  "404": {
33213
- "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).",
35629
+ "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
33214
35630
  "content": {
33215
35631
  "application/json": {
33216
35632
  "schema": {
@@ -33224,7 +35640,6 @@
33224
35640
  "error_code": {
33225
35641
  "type": "string",
33226
35642
  "enum": [
33227
- "not_found",
33228
35643
  "account_not_found"
33229
35644
  ]
33230
35645
  }
@@ -33286,67 +35701,62 @@
33286
35701
  }
33287
35702
  }
33288
35703
  }
33289
- }
33290
- },
33291
- "/team": {
33292
- "get": {
33293
- "operationId": "team/list",
33294
- "summary": "List Teams",
35704
+ },
35705
+ "post": {
35706
+ "operationId": "organization/create",
35707
+ "summary": "Create Organization",
33295
35708
  "tags": [
33296
- "team"
35709
+ "organization"
33297
35710
  ],
33298
- "description": "List Teams",
33299
- "parameters": [
33300
- {
33301
- "schema": {
33302
- "type": "number",
33303
- "minimum": 1,
33304
- "maximum": 200
33305
- },
33306
- "in": "query",
33307
- "name": "pageSize",
33308
- "required": false,
33309
- "description": "Number of items per page (max 200)"
33310
- },
33311
- {
33312
- "schema": {
33313
- "type": "string"
33314
- },
33315
- "in": "query",
33316
- "name": "cursor",
33317
- "required": false,
33318
- "description": "Cursor for next page"
33319
- },
33320
- {
33321
- "schema": {
33322
- "type": "string"
33323
- },
33324
- "in": "query",
33325
- "name": "next",
33326
- "required": false,
33327
- "description": "Cursor returned by the previous page"
33328
- },
33329
- {
33330
- "schema": {
33331
- "type": "string"
33332
- },
33333
- "in": "query",
33334
- "name": "query",
33335
- "required": false,
33336
- "description": "Filter using a FaableQL query"
35711
+ "description": "Create Organization",
35712
+ "requestBody": {
35713
+ "required": true,
35714
+ "content": {
35715
+ "application/json": {
35716
+ "schema": {
35717
+ "type": "object",
35718
+ "required": [
35719
+ "name"
35720
+ ],
35721
+ "properties": {
35722
+ "name": {
35723
+ "type": "string",
35724
+ "minLength": 1,
35725
+ "description": "Human-readable name of the organization.",
35726
+ "example": "Acme Inc."
35727
+ },
35728
+ "description": {
35729
+ "type": "string",
35730
+ "description": "Optional free-form description."
35731
+ },
35732
+ "logo_url": {
35733
+ "type": "string",
35734
+ "format": "uri",
35735
+ "description": "Optional URL of the organization logo."
35736
+ },
35737
+ "admins": {
35738
+ "type": "array",
35739
+ "items": {
35740
+ "type": "string",
35741
+ "pattern": "^user_[0-9a-f]{24}$"
35742
+ },
35743
+ "uniqueItems": true,
35744
+ "description": "Initial admins (user ids of this tenant). Can be empty and filled later with `POST /organization/{organization_id}/admin`."
35745
+ },
35746
+ "metadata": {
35747
+ "type": "object",
35748
+ "properties": {},
35749
+ "additionalProperties": true,
35750
+ "description": "Add Metadata"
35751
+ }
35752
+ },
35753
+ "description": "OrganizationCreate",
35754
+ "additionalProperties": false
35755
+ }
35756
+ }
33337
35757
  },
33338
- {
33339
- "schema": {
33340
- "type": "string",
33341
- "minLength": 1,
33342
- "maxLength": 200
33343
- },
33344
- "in": "query",
33345
- "name": "q",
33346
- "required": false,
33347
- "description": "Full-text search across: `name`, `slug`."
33348
- }
33349
- ],
35758
+ "description": "OrganizationCreate"
35759
+ },
33350
35760
  "security": [
33351
35761
  {
33352
35762
  "bearerAuth": []
@@ -33354,40 +35764,80 @@
33354
35764
  ],
33355
35765
  "responses": {
33356
35766
  "200": {
33357
- "description": "Default Response",
35767
+ "description": "Organization",
33358
35768
  "content": {
33359
35769
  "application/json": {
33360
35770
  "schema": {
33361
35771
  "type": "object",
33362
35772
  "required": [
33363
- "next",
33364
- "results"
35773
+ "id",
35774
+ "name",
35775
+ "slug",
35776
+ "description",
35777
+ "logo_url",
35778
+ "admins",
35779
+ "account",
35780
+ "createdAt"
33365
35781
  ],
33366
35782
  "properties": {
33367
- "next": {
33368
- "anyOf": [
33369
- {
33370
- "type": "string"
33371
- },
33372
- {
33373
- "type": "null"
33374
- }
33375
- ]
35783
+ "id": {
35784
+ "type": "string",
35785
+ "description": "Organization ID"
33376
35786
  },
33377
- "results": {
35787
+ "name": {
35788
+ "type": "string",
35789
+ "description": "Human-readable name of the organization.",
35790
+ "example": "Acme Inc."
35791
+ },
35792
+ "slug": {
35793
+ "type": "string",
35794
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
35795
+ "example": "acme-inc"
35796
+ },
35797
+ "description": {
35798
+ "type": "string",
35799
+ "description": "Optional free-form description.",
35800
+ "nullable": true
35801
+ },
35802
+ "logo_url": {
35803
+ "type": "string",
35804
+ "description": "Optional URL of the organization logo.",
35805
+ "nullable": true
35806
+ },
35807
+ "admins": {
33378
35808
  "type": "array",
33379
35809
  "items": {
33380
- "$ref": "#/components/schemas/Team"
33381
- }
35810
+ "type": "string"
35811
+ },
35812
+ "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."
35813
+ },
35814
+ "account": {
35815
+ "type": "string",
35816
+ "description": "Object is related with this account"
35817
+ },
35818
+ "metadata": {
35819
+ "type": "object",
35820
+ "properties": {},
35821
+ "additionalProperties": true,
35822
+ "description": "OrganizationMetadata",
35823
+ "default": {}
35824
+ },
35825
+ "createdAt": {
35826
+ "type": "string",
35827
+ "description": "Organization creation date"
35828
+ },
35829
+ "updatedAt": {
35830
+ "type": "string",
35831
+ "description": "Organization updated date"
33382
35832
  }
33383
35833
  },
33384
- "additionalProperties": false
35834
+ "description": "Organization"
33385
35835
  }
33386
35836
  }
33387
35837
  }
33388
35838
  },
33389
35839
  "400": {
33390
- "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.",
35840
+ "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.",
33391
35841
  "content": {
33392
35842
  "application/json": {
33393
35843
  "schema": {
@@ -33401,9 +35851,7 @@
33401
35851
  "error_code": {
33402
35852
  "type": "string",
33403
35853
  "enum": [
33404
- "invalid_query",
33405
- "invalid_expand",
33406
- "search_not_supported",
35854
+ "already_exists",
33407
35855
  "validation_error"
33408
35856
  ]
33409
35857
  }
@@ -33542,47 +35990,26 @@
33542
35990
  }
33543
35991
  }
33544
35992
  }
33545
- },
33546
- "post": {
33547
- "operationId": "team/create",
33548
- "summary": "Create Team",
35993
+ }
35994
+ },
35995
+ "/organization/{organization_id}": {
35996
+ "get": {
35997
+ "operationId": "organization/get",
35998
+ "summary": "Get Organization",
33549
35999
  "tags": [
33550
- "team"
36000
+ "organization"
36001
+ ],
36002
+ "description": "Get Organization",
36003
+ "parameters": [
36004
+ {
36005
+ "schema": {
36006
+ "type": "string"
36007
+ },
36008
+ "in": "path",
36009
+ "name": "organization_id",
36010
+ "required": true
36011
+ }
33551
36012
  ],
33552
- "description": "Create Team",
33553
- "requestBody": {
33554
- "required": true,
33555
- "content": {
33556
- "application/json": {
33557
- "schema": {
33558
- "type": "object",
33559
- "required": [
33560
- "name"
33561
- ],
33562
- "properties": {
33563
- "name": {
33564
- "type": "string",
33565
- "description": "Human-readable name of the team.",
33566
- "example": "Acme Engineering"
33567
- },
33568
- "description": {
33569
- "type": "string",
33570
- "description": "Optional free-form description of the team."
33571
- },
33572
- "metadata": {
33573
- "type": "object",
33574
- "properties": {},
33575
- "additionalProperties": true,
33576
- "description": "Add Metadata"
33577
- }
33578
- },
33579
- "description": "TeamCreate",
33580
- "additionalProperties": false
33581
- }
33582
- }
33583
- },
33584
- "description": "TeamCreate"
33585
- },
33586
36013
  "security": [
33587
36014
  {
33588
36015
  "bearerAuth": []
@@ -33590,7 +36017,7 @@
33590
36017
  ],
33591
36018
  "responses": {
33592
36019
  "200": {
33593
- "description": "Team",
36020
+ "description": "Organization",
33594
36021
  "content": {
33595
36022
  "application/json": {
33596
36023
  "schema": {
@@ -33601,34 +36028,42 @@
33601
36028
  "slug",
33602
36029
  "description",
33603
36030
  "logo_url",
36031
+ "admins",
33604
36032
  "account",
33605
36033
  "createdAt"
33606
36034
  ],
33607
36035
  "properties": {
33608
36036
  "id": {
33609
36037
  "type": "string",
33610
- "description": "Team ID"
36038
+ "description": "Organization ID"
33611
36039
  },
33612
36040
  "name": {
33613
36041
  "type": "string",
33614
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
33615
- "example": "Acme Engineering"
36042
+ "description": "Human-readable name of the organization.",
36043
+ "example": "Acme Inc."
33616
36044
  },
33617
36045
  "slug": {
33618
36046
  "type": "string",
33619
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
33620
- "example": "acme-engineering"
36047
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
36048
+ "example": "acme-inc"
33621
36049
  },
33622
36050
  "description": {
33623
36051
  "type": "string",
33624
- "description": "Optional free-form description of the team.",
36052
+ "description": "Optional free-form description.",
33625
36053
  "nullable": true
33626
36054
  },
33627
36055
  "logo_url": {
33628
36056
  "type": "string",
33629
- "description": "Optional URL of an image used as the team avatar/logo.",
36057
+ "description": "Optional URL of the organization logo.",
33630
36058
  "nullable": true
33631
36059
  },
36060
+ "admins": {
36061
+ "type": "array",
36062
+ "items": {
36063
+ "type": "string"
36064
+ },
36065
+ "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."
36066
+ },
33632
36067
  "account": {
33633
36068
  "type": "string",
33634
36069
  "description": "Object is related with this account"
@@ -33637,25 +36072,25 @@
33637
36072
  "type": "object",
33638
36073
  "properties": {},
33639
36074
  "additionalProperties": true,
33640
- "description": "TeamMetadata",
36075
+ "description": "OrganizationMetadata",
33641
36076
  "default": {}
33642
36077
  },
33643
36078
  "createdAt": {
33644
36079
  "type": "string",
33645
- "description": "Team creation date"
36080
+ "description": "Organization creation date"
33646
36081
  },
33647
36082
  "updatedAt": {
33648
36083
  "type": "string",
33649
- "description": "Team updated date"
36084
+ "description": "Organization updated date"
33650
36085
  }
33651
36086
  },
33652
- "description": "Team"
36087
+ "description": "Organization"
33653
36088
  }
33654
36089
  }
33655
36090
  }
33656
36091
  },
33657
36092
  "400": {
33658
- "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.",
36093
+ "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.",
33659
36094
  "content": {
33660
36095
  "application/json": {
33661
36096
  "schema": {
@@ -33669,7 +36104,8 @@
33669
36104
  "error_code": {
33670
36105
  "type": "string",
33671
36106
  "enum": [
33672
- "already_exists",
36107
+ "invalid_id",
36108
+ "invalid_expand",
33673
36109
  "validation_error"
33674
36110
  ]
33675
36111
  }
@@ -33733,7 +36169,7 @@
33733
36169
  }
33734
36170
  },
33735
36171
  "404": {
33736
- "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
36172
+ "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).",
33737
36173
  "content": {
33738
36174
  "application/json": {
33739
36175
  "schema": {
@@ -33747,6 +36183,7 @@
33747
36183
  "error_code": {
33748
36184
  "type": "string",
33749
36185
  "enum": [
36186
+ "not_found",
33750
36187
  "account_not_found"
33751
36188
  ]
33752
36189
  }
@@ -33808,23 +36245,56 @@
33808
36245
  }
33809
36246
  }
33810
36247
  }
33811
- }
33812
- },
33813
- "/team/{team_id}": {
33814
- "get": {
33815
- "operationId": "team/get",
33816
- "summary": "Get Team",
36248
+ },
36249
+ "post": {
36250
+ "operationId": "organization/update",
36251
+ "summary": "Update Organization",
33817
36252
  "tags": [
33818
- "team"
36253
+ "organization"
33819
36254
  ],
33820
- "description": "Get Team",
36255
+ "description": "Update Organization",
36256
+ "requestBody": {
36257
+ "required": true,
36258
+ "content": {
36259
+ "application/json": {
36260
+ "schema": {
36261
+ "type": "object",
36262
+ "properties": {
36263
+ "name": {
36264
+ "type": "string",
36265
+ "minLength": 1,
36266
+ "description": "New human-readable name."
36267
+ },
36268
+ "description": {
36269
+ "type": "string",
36270
+ "description": "New free-form description."
36271
+ },
36272
+ "logo_url": {
36273
+ "type": "string",
36274
+ "format": "uri",
36275
+ "description": "New URL of the organization logo."
36276
+ },
36277
+ "metadata": {
36278
+ "type": "object",
36279
+ "properties": {},
36280
+ "additionalProperties": true,
36281
+ "description": "Arbitrary key/value pairs. Replaces the previous metadata entirely."
36282
+ }
36283
+ },
36284
+ "description": "Partial update for an Organization. `slug` is derived from `name` on creation and is not editable; admins change through `/organization/{organization_id}/admin`.",
36285
+ "additionalProperties": false
36286
+ }
36287
+ }
36288
+ },
36289
+ "description": "Partial update for an Organization. `slug` is derived from `name` on creation and is not editable; admins change through `/organization/{organization_id}/admin`."
36290
+ },
33821
36291
  "parameters": [
33822
36292
  {
33823
36293
  "schema": {
33824
36294
  "type": "string"
33825
36295
  },
33826
36296
  "in": "path",
33827
- "name": "team_id",
36297
+ "name": "organization_id",
33828
36298
  "required": true
33829
36299
  }
33830
36300
  ],
@@ -33835,7 +36305,7 @@
33835
36305
  ],
33836
36306
  "responses": {
33837
36307
  "200": {
33838
- "description": "Team",
36308
+ "description": "Organization",
33839
36309
  "content": {
33840
36310
  "application/json": {
33841
36311
  "schema": {
@@ -33846,34 +36316,42 @@
33846
36316
  "slug",
33847
36317
  "description",
33848
36318
  "logo_url",
36319
+ "admins",
33849
36320
  "account",
33850
36321
  "createdAt"
33851
36322
  ],
33852
36323
  "properties": {
33853
36324
  "id": {
33854
36325
  "type": "string",
33855
- "description": "Team ID"
36326
+ "description": "Organization ID"
33856
36327
  },
33857
36328
  "name": {
33858
36329
  "type": "string",
33859
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
33860
- "example": "Acme Engineering"
36330
+ "description": "Human-readable name of the organization.",
36331
+ "example": "Acme Inc."
33861
36332
  },
33862
36333
  "slug": {
33863
36334
  "type": "string",
33864
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
33865
- "example": "acme-engineering"
36335
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
36336
+ "example": "acme-inc"
33866
36337
  },
33867
36338
  "description": {
33868
36339
  "type": "string",
33869
- "description": "Optional free-form description of the team.",
36340
+ "description": "Optional free-form description.",
33870
36341
  "nullable": true
33871
36342
  },
33872
36343
  "logo_url": {
33873
36344
  "type": "string",
33874
- "description": "Optional URL of an image used as the team avatar/logo.",
36345
+ "description": "Optional URL of the organization logo.",
33875
36346
  "nullable": true
33876
36347
  },
36348
+ "admins": {
36349
+ "type": "array",
36350
+ "items": {
36351
+ "type": "string"
36352
+ },
36353
+ "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."
36354
+ },
33877
36355
  "account": {
33878
36356
  "type": "string",
33879
36357
  "description": "Object is related with this account"
@@ -33882,25 +36360,25 @@
33882
36360
  "type": "object",
33883
36361
  "properties": {},
33884
36362
  "additionalProperties": true,
33885
- "description": "TeamMetadata",
36363
+ "description": "OrganizationMetadata",
33886
36364
  "default": {}
33887
36365
  },
33888
36366
  "createdAt": {
33889
36367
  "type": "string",
33890
- "description": "Team creation date"
36368
+ "description": "Organization creation date"
33891
36369
  },
33892
36370
  "updatedAt": {
33893
36371
  "type": "string",
33894
- "description": "Team updated date"
36372
+ "description": "Organization updated date"
33895
36373
  }
33896
36374
  },
33897
- "description": "Team"
36375
+ "description": "Organization"
33898
36376
  }
33899
36377
  }
33900
36378
  }
33901
36379
  },
33902
36380
  "400": {
33903
- "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.",
36381
+ "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.",
33904
36382
  "content": {
33905
36383
  "application/json": {
33906
36384
  "schema": {
@@ -33915,7 +36393,7 @@
33915
36393
  "type": "string",
33916
36394
  "enum": [
33917
36395
  "invalid_id",
33918
- "invalid_expand",
36396
+ "already_exists",
33919
36397
  "validation_error"
33920
36398
  ]
33921
36399
  }
@@ -34056,49 +36534,20 @@
34056
36534
  }
34057
36535
  }
34058
36536
  },
34059
- "post": {
34060
- "operationId": "team/update",
34061
- "summary": "Update Team",
36537
+ "delete": {
36538
+ "operationId": "organization/delete",
36539
+ "summary": "Delete Organization",
34062
36540
  "tags": [
34063
- "team"
36541
+ "organization"
34064
36542
  ],
34065
- "description": "Update Team",
34066
- "requestBody": {
34067
- "required": true,
34068
- "content": {
34069
- "application/json": {
34070
- "schema": {
34071
- "type": "object",
34072
- "properties": {
34073
- "name": {
34074
- "type": "string",
34075
- "description": "New human-readable name for the team."
34076
- },
34077
- "description": {
34078
- "type": "string",
34079
- "description": "New free-form description for the team."
34080
- },
34081
- "metadata": {
34082
- "type": "object",
34083
- "properties": {},
34084
- "additionalProperties": true,
34085
- "description": "Arbitrary key/value pairs attached to the team. Replaces the previous metadata entirely."
34086
- }
34087
- },
34088
- "description": "Partial update for a Team. Only the supplied fields are modified. `slug` is auto-derived from `name` and is not user-editable.",
34089
- "additionalProperties": false
34090
- }
34091
- }
34092
- },
34093
- "description": "Partial update for a Team. Only the supplied fields are modified. `slug` is auto-derived from `name` and is not user-editable."
34094
- },
36543
+ "description": "Delete Organization",
34095
36544
  "parameters": [
34096
36545
  {
34097
36546
  "schema": {
34098
36547
  "type": "string"
34099
36548
  },
34100
36549
  "in": "path",
34101
- "name": "team_id",
36550
+ "name": "organization_id",
34102
36551
  "required": true
34103
36552
  }
34104
36553
  ],
@@ -34109,7 +36558,7 @@
34109
36558
  ],
34110
36559
  "responses": {
34111
36560
  "200": {
34112
- "description": "Team",
36561
+ "description": "Organization",
34113
36562
  "content": {
34114
36563
  "application/json": {
34115
36564
  "schema": {
@@ -34120,34 +36569,42 @@
34120
36569
  "slug",
34121
36570
  "description",
34122
36571
  "logo_url",
36572
+ "admins",
34123
36573
  "account",
34124
36574
  "createdAt"
34125
36575
  ],
34126
36576
  "properties": {
34127
36577
  "id": {
34128
36578
  "type": "string",
34129
- "description": "Team ID"
36579
+ "description": "Organization ID"
34130
36580
  },
34131
36581
  "name": {
34132
36582
  "type": "string",
34133
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34134
- "example": "Acme Engineering"
36583
+ "description": "Human-readable name of the organization.",
36584
+ "example": "Acme Inc."
34135
36585
  },
34136
36586
  "slug": {
34137
36587
  "type": "string",
34138
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34139
- "example": "acme-engineering"
36588
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
36589
+ "example": "acme-inc"
34140
36590
  },
34141
36591
  "description": {
34142
36592
  "type": "string",
34143
- "description": "Optional free-form description of the team.",
36593
+ "description": "Optional free-form description.",
34144
36594
  "nullable": true
34145
36595
  },
34146
36596
  "logo_url": {
34147
36597
  "type": "string",
34148
- "description": "Optional URL of an image used as the team avatar/logo.",
36598
+ "description": "Optional URL of the organization logo.",
34149
36599
  "nullable": true
34150
36600
  },
36601
+ "admins": {
36602
+ "type": "array",
36603
+ "items": {
36604
+ "type": "string"
36605
+ },
36606
+ "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."
36607
+ },
34151
36608
  "account": {
34152
36609
  "type": "string",
34153
36610
  "description": "Object is related with this account"
@@ -34156,25 +36613,25 @@
34156
36613
  "type": "object",
34157
36614
  "properties": {},
34158
36615
  "additionalProperties": true,
34159
- "description": "TeamMetadata",
36616
+ "description": "OrganizationMetadata",
34160
36617
  "default": {}
34161
36618
  },
34162
36619
  "createdAt": {
34163
36620
  "type": "string",
34164
- "description": "Team creation date"
36621
+ "description": "Organization creation date"
34165
36622
  },
34166
36623
  "updatedAt": {
34167
36624
  "type": "string",
34168
- "description": "Team updated date"
36625
+ "description": "Organization updated date"
34169
36626
  }
34170
36627
  },
34171
- "description": "Team"
36628
+ "description": "Organization"
34172
36629
  }
34173
36630
  }
34174
36631
  }
34175
36632
  },
34176
36633
  "400": {
34177
- "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.",
36634
+ "description": "`invalid_id` — The id in the path is not a valid id for this resource.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
34178
36635
  "content": {
34179
36636
  "application/json": {
34180
36637
  "schema": {
@@ -34189,7 +36646,6 @@
34189
36646
  "type": "string",
34190
36647
  "enum": [
34191
36648
  "invalid_id",
34192
- "already_exists",
34193
36649
  "validation_error"
34194
36650
  ]
34195
36651
  }
@@ -34329,21 +36785,44 @@
34329
36785
  }
34330
36786
  }
34331
36787
  }
34332
- },
34333
- "delete": {
34334
- "operationId": "team/delete",
34335
- "summary": "Delete Team",
36788
+ }
36789
+ },
36790
+ "/organization/{organization_id}/admin": {
36791
+ "post": {
36792
+ "operationId": "organization/addAdmin",
36793
+ "summary": "Add an admin to an Organization",
34336
36794
  "tags": [
34337
- "team"
36795
+ "organization"
34338
36796
  ],
34339
- "description": "Delete Team",
36797
+ "description": "Makes a user of this tenant an admin of the Organization. Idempotent. Being an admin does not grant access to any team of the organization. Emits `organization.updated`.",
36798
+ "requestBody": {
36799
+ "required": true,
36800
+ "content": {
36801
+ "application/json": {
36802
+ "schema": {
36803
+ "type": "object",
36804
+ "required": [
36805
+ "user_id"
36806
+ ],
36807
+ "properties": {
36808
+ "user_id": {
36809
+ "type": "string",
36810
+ "description": "Id of a user of this tenant.",
36811
+ "example": "user_6555fd29a1b2c3d4e5f60718"
36812
+ }
36813
+ },
36814
+ "additionalProperties": false
36815
+ }
36816
+ }
36817
+ }
36818
+ },
34340
36819
  "parameters": [
34341
36820
  {
34342
36821
  "schema": {
34343
36822
  "type": "string"
34344
36823
  },
34345
36824
  "in": "path",
34346
- "name": "team_id",
36825
+ "name": "organization_id",
34347
36826
  "required": true
34348
36827
  }
34349
36828
  ],
@@ -34354,7 +36833,7 @@
34354
36833
  ],
34355
36834
  "responses": {
34356
36835
  "200": {
34357
- "description": "Team",
36836
+ "description": "Organization",
34358
36837
  "content": {
34359
36838
  "application/json": {
34360
36839
  "schema": {
@@ -34365,34 +36844,42 @@
34365
36844
  "slug",
34366
36845
  "description",
34367
36846
  "logo_url",
36847
+ "admins",
34368
36848
  "account",
34369
36849
  "createdAt"
34370
36850
  ],
34371
36851
  "properties": {
34372
36852
  "id": {
34373
36853
  "type": "string",
34374
- "description": "Team ID"
36854
+ "description": "Organization ID"
34375
36855
  },
34376
36856
  "name": {
34377
36857
  "type": "string",
34378
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34379
- "example": "Acme Engineering"
36858
+ "description": "Human-readable name of the organization.",
36859
+ "example": "Acme Inc."
34380
36860
  },
34381
36861
  "slug": {
34382
36862
  "type": "string",
34383
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34384
- "example": "acme-engineering"
36863
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
36864
+ "example": "acme-inc"
34385
36865
  },
34386
36866
  "description": {
34387
36867
  "type": "string",
34388
- "description": "Optional free-form description of the team.",
36868
+ "description": "Optional free-form description.",
34389
36869
  "nullable": true
34390
36870
  },
34391
36871
  "logo_url": {
34392
36872
  "type": "string",
34393
- "description": "Optional URL of an image used as the team avatar/logo.",
36873
+ "description": "Optional URL of the organization logo.",
34394
36874
  "nullable": true
34395
36875
  },
36876
+ "admins": {
36877
+ "type": "array",
36878
+ "items": {
36879
+ "type": "string"
36880
+ },
36881
+ "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."
36882
+ },
34396
36883
  "account": {
34397
36884
  "type": "string",
34398
36885
  "description": "Object is related with this account"
@@ -34401,25 +36888,25 @@
34401
36888
  "type": "object",
34402
36889
  "properties": {},
34403
36890
  "additionalProperties": true,
34404
- "description": "TeamMetadata",
36891
+ "description": "OrganizationMetadata",
34405
36892
  "default": {}
34406
36893
  },
34407
36894
  "createdAt": {
34408
36895
  "type": "string",
34409
- "description": "Team creation date"
36896
+ "description": "Organization creation date"
34410
36897
  },
34411
36898
  "updatedAt": {
34412
36899
  "type": "string",
34413
- "description": "Team updated date"
36900
+ "description": "Organization updated date"
34414
36901
  }
34415
36902
  },
34416
- "description": "Team"
36903
+ "description": "Organization"
34417
36904
  }
34418
36905
  }
34419
36906
  }
34420
36907
  },
34421
36908
  "400": {
34422
- "description": "`invalid_id` — The id in the path is not a valid id for this resource.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
36909
+ "description": "`invalid_user` — The user does not exist in this account.\n\n`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
34423
36910
  "content": {
34424
36911
  "application/json": {
34425
36912
  "schema": {
@@ -34433,7 +36920,7 @@
34433
36920
  "error_code": {
34434
36921
  "type": "string",
34435
36922
  "enum": [
34436
- "invalid_id",
36923
+ "invalid_user",
34437
36924
  "validation_error"
34438
36925
  ]
34439
36926
  }
@@ -34497,7 +36984,7 @@
34497
36984
  }
34498
36985
  },
34499
36986
  "404": {
34500
- "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).",
36987
+ "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).",
34501
36988
  "content": {
34502
36989
  "application/json": {
34503
36990
  "schema": {
@@ -34511,7 +36998,7 @@
34511
36998
  "error_code": {
34512
36999
  "type": "string",
34513
37000
  "enum": [
34514
- "not_found",
37001
+ "organization_not_found",
34515
37002
  "account_not_found"
34516
37003
  ]
34517
37004
  }
@@ -34573,65 +37060,32 @@
34573
37060
  }
34574
37061
  }
34575
37062
  }
34576
- },
34577
- "put": {
34578
- "operationId": "team/put",
34579
- "summary": "Create or update a Team with a given id",
37063
+ }
37064
+ },
37065
+ "/organization/{organization_id}/admin/{user_id}": {
37066
+ "delete": {
37067
+ "operationId": "organization/removeAdmin",
37068
+ "summary": "Remove an admin from an Organization",
34580
37069
  "tags": [
34581
- "team"
37070
+ "organization"
34582
37071
  ],
34583
- "description": "Creates the Team with the given id if it does not exist in this tenant (201), or updates its name, description, metadata and — when given — slug (200). Idempotent. Needs both `create:teams` and `update:teams`. `team_id_unavailable` (409) when the id cannot be used in this tenant; `already_exists` when the slug is taken by another team.",
34584
- "requestBody": {
34585
- "required": true,
34586
- "content": {
34587
- "application/json": {
34588
- "schema": {
34589
- "type": "object",
34590
- "required": [
34591
- "name"
34592
- ],
34593
- "properties": {
34594
- "name": {
34595
- "type": "string",
34596
- "minLength": 1,
34597
- "description": "Human-readable name of the team.",
34598
- "example": "Acme Engineering"
34599
- },
34600
- "slug": {
34601
- "type": "string",
34602
- "minLength": 1,
34603
- "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
34604
- "description": "URL-safe identifier, unique within the tenant. Derived from `name` when omitted on creation; when given, it is set as-is (also on update). Pass it when names can repeat.",
34605
- "example": "acme-engineering"
34606
- },
34607
- "description": {
34608
- "type": "string",
34609
- "description": "Optional free-form description."
34610
- },
34611
- "metadata": {
34612
- "type": "object",
34613
- "properties": {},
34614
- "additionalProperties": true,
34615
- "description": "Arbitrary key/value pairs attached to the team. Replaces the previous metadata entirely."
34616
- }
34617
- },
34618
- "additionalProperties": false,
34619
- "description": "Payload for creating or updating a Team under a caller-chosen id."
34620
- }
34621
- }
34622
- },
34623
- "description": "Payload for creating or updating a Team under a caller-chosen id."
34624
- },
37072
+ "description": "Removes the user from the admins of the Organization (the user is not deleted). An organization keeps at least one admin: removing the last one is `last_organization_admin`. Emits `organization.updated`.",
34625
37073
  "parameters": [
34626
37074
  {
34627
37075
  "schema": {
34628
- "type": "string",
34629
- "pattern": "^team_[0-9a-f]{24}$"
37076
+ "type": "string"
34630
37077
  },
34631
37078
  "in": "path",
34632
- "name": "team_id",
34633
- "required": true,
34634
- "description": "Id of the team to create or update: `team_` followed by 24 lowercase hex characters, chosen by the caller."
37079
+ "name": "organization_id",
37080
+ "required": true
37081
+ },
37082
+ {
37083
+ "schema": {
37084
+ "type": "string"
37085
+ },
37086
+ "in": "path",
37087
+ "name": "user_id",
37088
+ "required": true
34635
37089
  }
34636
37090
  ],
34637
37091
  "security": [
@@ -34641,7 +37095,7 @@
34641
37095
  ],
34642
37096
  "responses": {
34643
37097
  "200": {
34644
- "description": "Team",
37098
+ "description": "Organization",
34645
37099
  "content": {
34646
37100
  "application/json": {
34647
37101
  "schema": {
@@ -34652,98 +37106,41 @@
34652
37106
  "slug",
34653
37107
  "description",
34654
37108
  "logo_url",
37109
+ "admins",
34655
37110
  "account",
34656
37111
  "createdAt"
34657
37112
  ],
34658
37113
  "properties": {
34659
37114
  "id": {
34660
37115
  "type": "string",
34661
- "description": "Team ID"
37116
+ "description": "Organization ID"
34662
37117
  },
34663
37118
  "name": {
34664
37119
  "type": "string",
34665
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34666
- "example": "Acme Engineering"
37120
+ "description": "Human-readable name of the organization.",
37121
+ "example": "Acme Inc."
34667
37122
  },
34668
37123
  "slug": {
34669
37124
  "type": "string",
34670
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34671
- "example": "acme-engineering"
37125
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
37126
+ "example": "acme-inc"
34672
37127
  },
34673
37128
  "description": {
34674
37129
  "type": "string",
34675
- "description": "Optional free-form description of the team.",
37130
+ "description": "Optional free-form description.",
34676
37131
  "nullable": true
34677
37132
  },
34678
37133
  "logo_url": {
34679
37134
  "type": "string",
34680
- "description": "Optional URL of an image used as the team avatar/logo.",
34681
- "nullable": true
34682
- },
34683
- "account": {
34684
- "type": "string",
34685
- "description": "Object is related with this account"
34686
- },
34687
- "metadata": {
34688
- "type": "object",
34689
- "properties": {},
34690
- "additionalProperties": true,
34691
- "description": "TeamMetadata",
34692
- "default": {}
34693
- },
34694
- "createdAt": {
34695
- "type": "string",
34696
- "description": "Team creation date"
34697
- },
34698
- "updatedAt": {
34699
- "type": "string",
34700
- "description": "Team updated date"
34701
- }
34702
- },
34703
- "description": "Team"
34704
- }
34705
- }
34706
- }
34707
- },
34708
- "201": {
34709
- "description": "Team",
34710
- "content": {
34711
- "application/json": {
34712
- "schema": {
34713
- "type": "object",
34714
- "required": [
34715
- "id",
34716
- "name",
34717
- "slug",
34718
- "description",
34719
- "logo_url",
34720
- "account",
34721
- "createdAt"
34722
- ],
34723
- "properties": {
34724
- "id": {
34725
- "type": "string",
34726
- "description": "Team ID"
34727
- },
34728
- "name": {
34729
- "type": "string",
34730
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34731
- "example": "Acme Engineering"
34732
- },
34733
- "slug": {
34734
- "type": "string",
34735
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34736
- "example": "acme-engineering"
34737
- },
34738
- "description": {
34739
- "type": "string",
34740
- "description": "Optional free-form description of the team.",
37135
+ "description": "Optional URL of the organization logo.",
34741
37136
  "nullable": true
34742
37137
  },
34743
- "logo_url": {
34744
- "type": "string",
34745
- "description": "Optional URL of an image used as the team avatar/logo.",
34746
- "nullable": true
37138
+ "admins": {
37139
+ "type": "array",
37140
+ "items": {
37141
+ "type": "string"
37142
+ },
37143
+ "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."
34747
37144
  },
34748
37145
  "account": {
34749
37146
  "type": "string",
@@ -34753,25 +37150,25 @@
34753
37150
  "type": "object",
34754
37151
  "properties": {},
34755
37152
  "additionalProperties": true,
34756
- "description": "TeamMetadata",
37153
+ "description": "OrganizationMetadata",
34757
37154
  "default": {}
34758
37155
  },
34759
37156
  "createdAt": {
34760
37157
  "type": "string",
34761
- "description": "Team creation date"
37158
+ "description": "Organization creation date"
34762
37159
  },
34763
37160
  "updatedAt": {
34764
37161
  "type": "string",
34765
- "description": "Team updated date"
37162
+ "description": "Organization updated date"
34766
37163
  }
34767
37164
  },
34768
- "description": "Team"
37165
+ "description": "Organization"
34769
37166
  }
34770
37167
  }
34771
37168
  }
34772
37169
  },
34773
37170
  "400": {
34774
- "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.",
37171
+ "description": "`validation_error` — The body, query or path failed schema validation. `details.issues` lists each failing field.",
34775
37172
  "content": {
34776
37173
  "application/json": {
34777
37174
  "schema": {
@@ -34785,7 +37182,6 @@
34785
37182
  "error_code": {
34786
37183
  "type": "string",
34787
37184
  "enum": [
34788
- "already_exists",
34789
37185
  "validation_error"
34790
37186
  ]
34791
37187
  }
@@ -34849,7 +37245,7 @@
34849
37245
  }
34850
37246
  },
34851
37247
  "404": {
34852
- "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
37248
+ "description": "`organization_not_found` — No organization with that id in this account.\n\n`not_an_organization_admin` — The user is not an admin of the organization.\n\n`account_not_found` — No Auth Account matches the request (domain, header or token).",
34853
37249
  "content": {
34854
37250
  "application/json": {
34855
37251
  "schema": {
@@ -34863,6 +37259,8 @@
34863
37259
  "error_code": {
34864
37260
  "type": "string",
34865
37261
  "enum": [
37262
+ "organization_not_found",
37263
+ "not_an_organization_admin",
34866
37264
  "account_not_found"
34867
37265
  ]
34868
37266
  }
@@ -34874,7 +37272,7 @@
34874
37272
  }
34875
37273
  },
34876
37274
  "409": {
34877
- "description": "`team_id_unavailable` — The team id cannot be used in this tenant. Pick another id or let the API generate one.",
37275
+ "description": "`last_organization_admin` — An organization keeps at least one admin. Add another admin before removing this one.",
34878
37276
  "content": {
34879
37277
  "application/json": {
34880
37278
  "schema": {
@@ -34888,7 +37286,7 @@
34888
37286
  "error_code": {
34889
37287
  "type": "string",
34890
37288
  "enum": [
34891
- "team_id_unavailable"
37289
+ "last_organization_admin"
34892
37290
  ]
34893
37291
  }
34894
37292
  }
@@ -49845,7 +52243,7 @@
49845
52243
  "items": {
49846
52244
  "type": "string"
49847
52245
  },
49848
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
52246
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
49849
52247
  },
49850
52248
  "channel": {
49851
52249
  "type": "string",
@@ -49998,7 +52396,7 @@
49998
52396
  "items": {
49999
52397
  "type": "string"
50000
52398
  },
50001
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
52399
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
50002
52400
  },
50003
52401
  "channel": {
50004
52402
  "type": "string",
@@ -50368,7 +52766,7 @@
50368
52766
  "items": {
50369
52767
  "type": "string"
50370
52768
  },
50371
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
52769
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
50372
52770
  },
50373
52771
  "channel": {
50374
52772
  "type": "string",
@@ -50678,7 +53076,7 @@
50678
53076
  "items": {
50679
53077
  "type": "string"
50680
53078
  },
50681
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
53079
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
50682
53080
  },
50683
53081
  "channel": {
50684
53082
  "type": "string",
@@ -50835,7 +53233,7 @@
50835
53233
  "items": {
50836
53234
  "type": "string"
50837
53235
  },
50838
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
53236
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
50839
53237
  },
50840
53238
  "channel": {
50841
53239
  "type": "string",
@@ -51205,7 +53603,7 @@
51205
53603
  "items": {
51206
53604
  "type": "string"
51207
53605
  },
51208
- "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n\n`team.*` payloads are notices, not state: they carry ids (`team_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
53606
+ "description": "Events to subscribe to. For `webhook` subscriptions it must be a subset of the published catalog; any other value is rejected with a 400:\n\n- `user.created`: A user was created (signup, import or Management API).\n- `user.updated`: A user was updated.\n- `user.deleted`: A user was deleted.\n- `auth.login`: A user logged in.\n- `credentials.exported`: Someone exported the tenant's password hashes (`GET /user/export` with hashes).\n- `team.created`: A team was created.\n- `team.updated`: A team was updated.\n- `team.deleted`: A team was deleted.\n- `team.member.added`: A user was added to a team.\n- `team.member.updated`: A team member's roles changed.\n- `team.member.removed`: A user was removed from a team (or left it).\n- `team.invite.created`: An invitation to join a team was created.\n- `team.invite.revoked`: A pending team invitation was revoked.\n- `team.invite.accepted`: A team invitation was accepted.\n- `organization.created`: An organization was created.\n- `organization.updated`: An organization was updated (name, settings or admins).\n- `organization.deleted`: An organization was deleted. Its teams are no longer in any organization; no `team.updated` is sent for them.\n\n`team.*` and `organization.*` payloads are notices, not state: they carry ids (`team_id`, `organization_id`, `user_id`, `roles`, `invite_id`...) and the receiver reads whatever else it needs. Use the delivery id (`x-faable-delivery`) to deduplicate: retries keep it."
51209
53607
  },
51210
53608
  "channel": {
51211
53609
  "type": "string",
@@ -64658,7 +67056,7 @@
64658
67056
  "tags": [
64659
67057
  "oauth"
64660
67058
  ],
64661
- "description": "Register a new OAuth/OIDC client dynamically (OIDC Dynamic Client Registration 1.0 / RFC 7591). The new client is bound to the Account resolved from the request context.",
67059
+ "description": "Register a new OAuth/OIDC client dynamically (OIDC Dynamic Client Registration 1.0 / RFC 7591). The new client is bound to the Account resolved from the request context. Only when the tenant has `dynamic_client_registration_enabled`; otherwise `registration_disabled` (403).",
64662
67060
  "requestBody": {
64663
67061
  "required": true,
64664
67062
  "content": {
@@ -64926,6 +67324,31 @@
64926
67324
  }
64927
67325
  }
64928
67326
  },
67327
+ "403": {
67328
+ "description": "`registration_disabled` — 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`.",
67329
+ "content": {
67330
+ "application/json": {
67331
+ "schema": {
67332
+ "allOf": [
67333
+ {
67334
+ "$ref": "#/components/schemas/ErrorResponse"
67335
+ },
67336
+ {
67337
+ "type": "object",
67338
+ "properties": {
67339
+ "error_code": {
67340
+ "type": "string",
67341
+ "enum": [
67342
+ "registration_disabled"
67343
+ ]
67344
+ }
67345
+ }
67346
+ }
67347
+ ]
67348
+ }
67349
+ }
67350
+ }
67351
+ },
64929
67352
  "404": {
64930
67353
  "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
64931
67354
  "content": {