@faable/auth-sdk 2.7.80 → 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.63.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
@@ -7437,6 +7602,10 @@
7437
7602
  "resource": {
7438
7603
  "type": "string",
7439
7604
  "description": "RFC 8707 Resource Indicator. Absolute URI of the target Api, no fragment. Matched against `Api.identifier` in the tenant."
7605
+ },
7606
+ "invalidate_token": {
7607
+ "type": "string",
7608
+ "description": "client_credentials only. An access token previously returned by this endpoint that a resource server rejected with 401. If it is the cached token for this client, the cache entry is dropped and a new token is issued; otherwise it has no effect."
7440
7609
  }
7441
7610
  },
7442
7611
  "additionalProperties": true
@@ -7611,7 +7780,7 @@
7611
7780
  },
7612
7781
  "ErrorCode": {
7613
7782
  "type": "string",
7614
- "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.",
7615
7784
  "enum": [
7616
7785
  "bad_request",
7617
7786
  "validation_error",
@@ -7731,6 +7900,11 @@
7731
7900
  "invite_used",
7732
7901
  "already_member",
7733
7902
  "not_a_member",
7903
+ "registration_disabled",
7904
+ "organization_not_found",
7905
+ "invalid_user",
7906
+ "not_an_organization_admin",
7907
+ "last_organization_admin",
7734
7908
  "team_id_unavailable",
7735
7909
  "use_team_member_route",
7736
7910
  "role_not_found",
@@ -8394,6 +8568,10 @@
8394
8568
  "type": "boolean",
8395
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)."
8396
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
+ },
8397
8575
  "canonical_host": {
8398
8576
  "type": "string",
8399
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.",
@@ -9138,6 +9316,10 @@
9138
9316
  "type": "boolean",
9139
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)."
9140
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
+ },
9141
9323
  "canonical_host": {
9142
9324
  "type": "string",
9143
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.",
@@ -10119,6 +10301,10 @@
10119
10301
  "type": "boolean",
10120
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)."
10121
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
+ },
10122
10308
  "canonical_host": {
10123
10309
  "type": "string",
10124
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.",
@@ -10744,6 +10930,10 @@
10744
10930
  }
10745
10931
  ]
10746
10932
  },
10933
+ "dynamic_client_registration_enabled": {
10934
+ "type": "boolean",
10935
+ "nullable": true
10936
+ },
10747
10937
  "canonical_host": {
10748
10938
  "type": "string",
10749
10939
  "nullable": true
@@ -11276,6 +11466,10 @@
11276
11466
  "type": "boolean",
11277
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)."
11278
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
+ },
11279
11473
  "canonical_host": {
11280
11474
  "type": "string",
11281
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.",
@@ -14218,6 +14412,10 @@
14218
14412
  "type": "boolean",
14219
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)."
14220
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
+ },
14221
14419
  "canonical_host": {
14222
14420
  "type": "string",
14223
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.",
@@ -32771,39 +32969,2248 @@
32771
32969
  }
32772
32970
  }
32773
32971
  },
32774
- "/rolemember/{rolemember_id}": {
32775
- "get": {
32776
- "operationId": "rolemember/get",
32777
- "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",
32778
35182
  "tags": [
32779
- "rolemember"
35183
+ "team"
32780
35184
  ],
32781
- "description": "Get Rolemember",
32782
- "parameters": [
32783
- {
32784
- "schema": {
32785
- "type": "array",
32786
- "items": {
32787
- "type": "string",
32788
- "enum": [
32789
- "user",
32790
- "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"
32791
35194
  ],
32792
- "description": "Allowed expand paths on `rolemember`: `user`, `role`."
32793
- },
32794
- "maxItems": 2
32795
- },
32796
- "in": "query",
32797
- "name": "expand",
32798
- "required": false,
32799
- "description": "Expand id-only fields in the response. Pass one path per entry (e.g. `?expand=user`)."
32800
- },
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": [
32801
35208
  {
32802
35209
  "schema": {
32803
35210
  "type": "string"
32804
35211
  },
32805
35212
  "in": "path",
32806
- "name": "rolemember_id",
35213
+ "name": "team_id",
32807
35214
  "required": true
32808
35215
  }
32809
35216
  ],
@@ -32814,46 +35221,49 @@
32814
35221
  ],
32815
35222
  "responses": {
32816
35223
  "200": {
32817
- "description": "RoleMember",
35224
+ "description": "Team",
32818
35225
  "content": {
32819
35226
  "application/json": {
32820
35227
  "schema": {
32821
35228
  "type": "object",
32822
35229
  "required": [
32823
35230
  "id",
32824
- "role",
32825
- "user",
35231
+ "name",
35232
+ "slug",
35233
+ "description",
35234
+ "logo_url",
32826
35235
  "account",
32827
35236
  "createdAt"
32828
35237
  ],
32829
35238
  "properties": {
32830
35239
  "id": {
32831
35240
  "type": "string",
32832
- "description": "RoleMember ID"
35241
+ "description": "Team ID"
32833
35242
  },
32834
- "role": {
32835
- "anyOf": [
32836
- {
32837
- "$ref": "#/components/schemas/Role"
32838
- },
32839
- {
32840
- "type": "string"
32841
- },
32842
- {}
32843
- ],
32844
- "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"
32845
35247
  },
32846
- "user": {
32847
- "anyOf": [
32848
- {
32849
- "$ref": "#/components/schemas/User"
32850
- },
32851
- {
32852
- "type": "string"
32853
- },
32854
- {}
32855
- ],
32856
- "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
32857
35267
  },
32858
35268
  "account": {
32859
35269
  "type": "string",
@@ -32863,25 +35273,25 @@
32863
35273
  "type": "object",
32864
35274
  "properties": {},
32865
35275
  "additionalProperties": true,
32866
- "description": "RoleMemberMetadata",
35276
+ "description": "TeamMetadata",
32867
35277
  "default": {}
32868
35278
  },
32869
35279
  "createdAt": {
32870
35280
  "type": "string",
32871
- "description": "RoleMember creation date"
35281
+ "description": "Team creation date"
32872
35282
  },
32873
35283
  "updatedAt": {
32874
35284
  "type": "string",
32875
- "description": "RoleMember updated date"
35285
+ "description": "Team updated date"
32876
35286
  }
32877
35287
  },
32878
- "description": "RoleMember"
35288
+ "description": "Team"
32879
35289
  }
32880
35290
  }
32881
35291
  }
32882
35292
  },
32883
35293
  "400": {
32884
- "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.",
32885
35295
  "content": {
32886
35296
  "application/json": {
32887
35297
  "schema": {
@@ -32895,8 +35305,6 @@
32895
35305
  "error_code": {
32896
35306
  "type": "string",
32897
35307
  "enum": [
32898
- "invalid_id",
32899
- "invalid_expand",
32900
35308
  "validation_error"
32901
35309
  ]
32902
35310
  }
@@ -32960,7 +35368,7 @@
32960
35368
  }
32961
35369
  },
32962
35370
  "404": {
32963
- "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).",
32964
35372
  "content": {
32965
35373
  "application/json": {
32966
35374
  "schema": {
@@ -32975,6 +35383,7 @@
32975
35383
  "type": "string",
32976
35384
  "enum": [
32977
35385
  "not_found",
35386
+ "organization_not_found",
32978
35387
  "account_not_found"
32979
35388
  ]
32980
35389
  }
@@ -33036,22 +35445,65 @@
33036
35445
  }
33037
35446
  }
33038
35447
  }
33039
- },
33040
- "delete": {
33041
- "operationId": "rolemember/delete",
33042
- "summary": "Delete Rolemember",
35448
+ }
35449
+ },
35450
+ "/organization": {
35451
+ "get": {
35452
+ "operationId": "organization/list",
35453
+ "summary": "List Organizations",
33043
35454
  "tags": [
33044
- "rolemember"
35455
+ "organization"
33045
35456
  ],
33046
- "description": "Delete Rolemember",
35457
+ "description": "List Organizations",
33047
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
+ },
33048
35470
  {
33049
35471
  "schema": {
33050
35472
  "type": "string"
33051
35473
  },
33052
- "in": "path",
33053
- "name": "rolemember_id",
33054
- "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`."
33055
35507
  }
33056
35508
  ],
33057
35509
  "security": [
@@ -33061,74 +35513,40 @@
33061
35513
  ],
33062
35514
  "responses": {
33063
35515
  "200": {
33064
- "description": "RoleMember",
35516
+ "description": "Default Response",
33065
35517
  "content": {
33066
35518
  "application/json": {
33067
35519
  "schema": {
33068
35520
  "type": "object",
33069
35521
  "required": [
33070
- "id",
33071
- "role",
33072
- "user",
33073
- "account",
33074
- "createdAt"
35522
+ "next",
35523
+ "results"
33075
35524
  ],
33076
35525
  "properties": {
33077
- "id": {
33078
- "type": "string",
33079
- "description": "RoleMember ID"
33080
- },
33081
- "role": {
35526
+ "next": {
33082
35527
  "anyOf": [
33083
- {
33084
- "$ref": "#/components/schemas/Role"
33085
- },
33086
35528
  {
33087
35529
  "type": "string"
33088
35530
  },
33089
- {}
33090
- ],
33091
- "description": "Role granted to the user. Returned as an id by default; pass `?expand=role` to inline the full Role object."
33092
- },
33093
- "user": {
33094
- "anyOf": [
33095
35531
  {
33096
- "$ref": "#/components/schemas/User"
33097
- },
33098
- {
33099
- "type": "string"
33100
- },
33101
- {}
33102
- ],
33103
- "description": "User the role is granted to. Returned as an id by default; pass `?expand=user` to inline the full User object."
33104
- },
33105
- "account": {
33106
- "type": "string",
33107
- "description": "Object is related with this account"
33108
- },
33109
- "metadata": {
33110
- "type": "object",
33111
- "properties": {},
33112
- "additionalProperties": true,
33113
- "description": "RoleMemberMetadata",
33114
- "default": {}
33115
- },
33116
- "createdAt": {
33117
- "type": "string",
33118
- "description": "RoleMember creation date"
35532
+ "type": "null"
35533
+ }
35534
+ ]
33119
35535
  },
33120
- "updatedAt": {
33121
- "type": "string",
33122
- "description": "RoleMember updated date"
35536
+ "results": {
35537
+ "type": "array",
35538
+ "items": {
35539
+ "$ref": "#/components/schemas/Organization"
35540
+ }
33123
35541
  }
33124
35542
  },
33125
- "description": "RoleMember"
35543
+ "additionalProperties": false
33126
35544
  }
33127
35545
  }
33128
35546
  }
33129
35547
  },
33130
35548
  "400": {
33131
- "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.",
33132
35550
  "content": {
33133
35551
  "application/json": {
33134
35552
  "schema": {
@@ -33142,7 +35560,9 @@
33142
35560
  "error_code": {
33143
35561
  "type": "string",
33144
35562
  "enum": [
33145
- "invalid_id",
35563
+ "invalid_query",
35564
+ "invalid_expand",
35565
+ "search_not_supported",
33146
35566
  "validation_error"
33147
35567
  ]
33148
35568
  }
@@ -33206,7 +35626,7 @@
33206
35626
  }
33207
35627
  },
33208
35628
  "404": {
33209
- "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).",
33210
35630
  "content": {
33211
35631
  "application/json": {
33212
35632
  "schema": {
@@ -33220,7 +35640,6 @@
33220
35640
  "error_code": {
33221
35641
  "type": "string",
33222
35642
  "enum": [
33223
- "not_found",
33224
35643
  "account_not_found"
33225
35644
  ]
33226
35645
  }
@@ -33282,67 +35701,62 @@
33282
35701
  }
33283
35702
  }
33284
35703
  }
33285
- }
33286
- },
33287
- "/team": {
33288
- "get": {
33289
- "operationId": "team/list",
33290
- "summary": "List Teams",
35704
+ },
35705
+ "post": {
35706
+ "operationId": "organization/create",
35707
+ "summary": "Create Organization",
33291
35708
  "tags": [
33292
- "team"
35709
+ "organization"
33293
35710
  ],
33294
- "description": "List Teams",
33295
- "parameters": [
33296
- {
33297
- "schema": {
33298
- "type": "number",
33299
- "minimum": 1,
33300
- "maximum": 200
33301
- },
33302
- "in": "query",
33303
- "name": "pageSize",
33304
- "required": false,
33305
- "description": "Number of items per page (max 200)"
33306
- },
33307
- {
33308
- "schema": {
33309
- "type": "string"
33310
- },
33311
- "in": "query",
33312
- "name": "cursor",
33313
- "required": false,
33314
- "description": "Cursor for next page"
33315
- },
33316
- {
33317
- "schema": {
33318
- "type": "string"
33319
- },
33320
- "in": "query",
33321
- "name": "next",
33322
- "required": false,
33323
- "description": "Cursor returned by the previous page"
33324
- },
33325
- {
33326
- "schema": {
33327
- "type": "string"
33328
- },
33329
- "in": "query",
33330
- "name": "query",
33331
- "required": false,
33332
- "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
+ }
33333
35757
  },
33334
- {
33335
- "schema": {
33336
- "type": "string",
33337
- "minLength": 1,
33338
- "maxLength": 200
33339
- },
33340
- "in": "query",
33341
- "name": "q",
33342
- "required": false,
33343
- "description": "Full-text search across: `name`, `slug`."
33344
- }
33345
- ],
35758
+ "description": "OrganizationCreate"
35759
+ },
33346
35760
  "security": [
33347
35761
  {
33348
35762
  "bearerAuth": []
@@ -33350,40 +35764,80 @@
33350
35764
  ],
33351
35765
  "responses": {
33352
35766
  "200": {
33353
- "description": "Default Response",
35767
+ "description": "Organization",
33354
35768
  "content": {
33355
35769
  "application/json": {
33356
35770
  "schema": {
33357
35771
  "type": "object",
33358
35772
  "required": [
33359
- "next",
33360
- "results"
35773
+ "id",
35774
+ "name",
35775
+ "slug",
35776
+ "description",
35777
+ "logo_url",
35778
+ "admins",
35779
+ "account",
35780
+ "createdAt"
33361
35781
  ],
33362
35782
  "properties": {
33363
- "next": {
33364
- "anyOf": [
33365
- {
33366
- "type": "string"
33367
- },
33368
- {
33369
- "type": "null"
33370
- }
33371
- ]
35783
+ "id": {
35784
+ "type": "string",
35785
+ "description": "Organization ID"
33372
35786
  },
33373
- "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": {
33374
35808
  "type": "array",
33375
35809
  "items": {
33376
- "$ref": "#/components/schemas/Team"
33377
- }
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"
33378
35832
  }
33379
35833
  },
33380
- "additionalProperties": false
35834
+ "description": "Organization"
33381
35835
  }
33382
35836
  }
33383
35837
  }
33384
35838
  },
33385
35839
  "400": {
33386
- "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.",
33387
35841
  "content": {
33388
35842
  "application/json": {
33389
35843
  "schema": {
@@ -33397,9 +35851,7 @@
33397
35851
  "error_code": {
33398
35852
  "type": "string",
33399
35853
  "enum": [
33400
- "invalid_query",
33401
- "invalid_expand",
33402
- "search_not_supported",
35854
+ "already_exists",
33403
35855
  "validation_error"
33404
35856
  ]
33405
35857
  }
@@ -33538,47 +35990,26 @@
33538
35990
  }
33539
35991
  }
33540
35992
  }
33541
- },
33542
- "post": {
33543
- "operationId": "team/create",
33544
- "summary": "Create Team",
35993
+ }
35994
+ },
35995
+ "/organization/{organization_id}": {
35996
+ "get": {
35997
+ "operationId": "organization/get",
35998
+ "summary": "Get Organization",
33545
35999
  "tags": [
33546
- "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
+ }
33547
36012
  ],
33548
- "description": "Create Team",
33549
- "requestBody": {
33550
- "required": true,
33551
- "content": {
33552
- "application/json": {
33553
- "schema": {
33554
- "type": "object",
33555
- "required": [
33556
- "name"
33557
- ],
33558
- "properties": {
33559
- "name": {
33560
- "type": "string",
33561
- "description": "Human-readable name of the team.",
33562
- "example": "Acme Engineering"
33563
- },
33564
- "description": {
33565
- "type": "string",
33566
- "description": "Optional free-form description of the team."
33567
- },
33568
- "metadata": {
33569
- "type": "object",
33570
- "properties": {},
33571
- "additionalProperties": true,
33572
- "description": "Add Metadata"
33573
- }
33574
- },
33575
- "description": "TeamCreate",
33576
- "additionalProperties": false
33577
- }
33578
- }
33579
- },
33580
- "description": "TeamCreate"
33581
- },
33582
36013
  "security": [
33583
36014
  {
33584
36015
  "bearerAuth": []
@@ -33586,7 +36017,7 @@
33586
36017
  ],
33587
36018
  "responses": {
33588
36019
  "200": {
33589
- "description": "Team",
36020
+ "description": "Organization",
33590
36021
  "content": {
33591
36022
  "application/json": {
33592
36023
  "schema": {
@@ -33597,34 +36028,42 @@
33597
36028
  "slug",
33598
36029
  "description",
33599
36030
  "logo_url",
36031
+ "admins",
33600
36032
  "account",
33601
36033
  "createdAt"
33602
36034
  ],
33603
36035
  "properties": {
33604
36036
  "id": {
33605
36037
  "type": "string",
33606
- "description": "Team ID"
36038
+ "description": "Organization ID"
33607
36039
  },
33608
36040
  "name": {
33609
36041
  "type": "string",
33610
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
33611
- "example": "Acme Engineering"
36042
+ "description": "Human-readable name of the organization.",
36043
+ "example": "Acme Inc."
33612
36044
  },
33613
36045
  "slug": {
33614
36046
  "type": "string",
33615
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
33616
- "example": "acme-engineering"
36047
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
36048
+ "example": "acme-inc"
33617
36049
  },
33618
36050
  "description": {
33619
36051
  "type": "string",
33620
- "description": "Optional free-form description of the team.",
36052
+ "description": "Optional free-form description.",
33621
36053
  "nullable": true
33622
36054
  },
33623
36055
  "logo_url": {
33624
36056
  "type": "string",
33625
- "description": "Optional URL of an image used as the team avatar/logo.",
36057
+ "description": "Optional URL of the organization logo.",
33626
36058
  "nullable": true
33627
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
+ },
33628
36067
  "account": {
33629
36068
  "type": "string",
33630
36069
  "description": "Object is related with this account"
@@ -33633,25 +36072,25 @@
33633
36072
  "type": "object",
33634
36073
  "properties": {},
33635
36074
  "additionalProperties": true,
33636
- "description": "TeamMetadata",
36075
+ "description": "OrganizationMetadata",
33637
36076
  "default": {}
33638
36077
  },
33639
36078
  "createdAt": {
33640
36079
  "type": "string",
33641
- "description": "Team creation date"
36080
+ "description": "Organization creation date"
33642
36081
  },
33643
36082
  "updatedAt": {
33644
36083
  "type": "string",
33645
- "description": "Team updated date"
36084
+ "description": "Organization updated date"
33646
36085
  }
33647
36086
  },
33648
- "description": "Team"
36087
+ "description": "Organization"
33649
36088
  }
33650
36089
  }
33651
36090
  }
33652
36091
  },
33653
36092
  "400": {
33654
- "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.",
33655
36094
  "content": {
33656
36095
  "application/json": {
33657
36096
  "schema": {
@@ -33665,7 +36104,8 @@
33665
36104
  "error_code": {
33666
36105
  "type": "string",
33667
36106
  "enum": [
33668
- "already_exists",
36107
+ "invalid_id",
36108
+ "invalid_expand",
33669
36109
  "validation_error"
33670
36110
  ]
33671
36111
  }
@@ -33729,7 +36169,7 @@
33729
36169
  }
33730
36170
  },
33731
36171
  "404": {
33732
- "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).",
33733
36173
  "content": {
33734
36174
  "application/json": {
33735
36175
  "schema": {
@@ -33743,6 +36183,7 @@
33743
36183
  "error_code": {
33744
36184
  "type": "string",
33745
36185
  "enum": [
36186
+ "not_found",
33746
36187
  "account_not_found"
33747
36188
  ]
33748
36189
  }
@@ -33804,23 +36245,56 @@
33804
36245
  }
33805
36246
  }
33806
36247
  }
33807
- }
33808
- },
33809
- "/team/{team_id}": {
33810
- "get": {
33811
- "operationId": "team/get",
33812
- "summary": "Get Team",
36248
+ },
36249
+ "post": {
36250
+ "operationId": "organization/update",
36251
+ "summary": "Update Organization",
33813
36252
  "tags": [
33814
- "team"
36253
+ "organization"
33815
36254
  ],
33816
- "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
+ },
33817
36291
  "parameters": [
33818
36292
  {
33819
36293
  "schema": {
33820
36294
  "type": "string"
33821
36295
  },
33822
36296
  "in": "path",
33823
- "name": "team_id",
36297
+ "name": "organization_id",
33824
36298
  "required": true
33825
36299
  }
33826
36300
  ],
@@ -33831,7 +36305,7 @@
33831
36305
  ],
33832
36306
  "responses": {
33833
36307
  "200": {
33834
- "description": "Team",
36308
+ "description": "Organization",
33835
36309
  "content": {
33836
36310
  "application/json": {
33837
36311
  "schema": {
@@ -33842,34 +36316,42 @@
33842
36316
  "slug",
33843
36317
  "description",
33844
36318
  "logo_url",
36319
+ "admins",
33845
36320
  "account",
33846
36321
  "createdAt"
33847
36322
  ],
33848
36323
  "properties": {
33849
36324
  "id": {
33850
36325
  "type": "string",
33851
- "description": "Team ID"
36326
+ "description": "Organization ID"
33852
36327
  },
33853
36328
  "name": {
33854
36329
  "type": "string",
33855
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
33856
- "example": "Acme Engineering"
36330
+ "description": "Human-readable name of the organization.",
36331
+ "example": "Acme Inc."
33857
36332
  },
33858
36333
  "slug": {
33859
36334
  "type": "string",
33860
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
33861
- "example": "acme-engineering"
36335
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
36336
+ "example": "acme-inc"
33862
36337
  },
33863
36338
  "description": {
33864
36339
  "type": "string",
33865
- "description": "Optional free-form description of the team.",
36340
+ "description": "Optional free-form description.",
33866
36341
  "nullable": true
33867
36342
  },
33868
36343
  "logo_url": {
33869
36344
  "type": "string",
33870
- "description": "Optional URL of an image used as the team avatar/logo.",
36345
+ "description": "Optional URL of the organization logo.",
33871
36346
  "nullable": true
33872
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
+ },
33873
36355
  "account": {
33874
36356
  "type": "string",
33875
36357
  "description": "Object is related with this account"
@@ -33878,25 +36360,25 @@
33878
36360
  "type": "object",
33879
36361
  "properties": {},
33880
36362
  "additionalProperties": true,
33881
- "description": "TeamMetadata",
36363
+ "description": "OrganizationMetadata",
33882
36364
  "default": {}
33883
36365
  },
33884
36366
  "createdAt": {
33885
36367
  "type": "string",
33886
- "description": "Team creation date"
36368
+ "description": "Organization creation date"
33887
36369
  },
33888
36370
  "updatedAt": {
33889
36371
  "type": "string",
33890
- "description": "Team updated date"
36372
+ "description": "Organization updated date"
33891
36373
  }
33892
36374
  },
33893
- "description": "Team"
36375
+ "description": "Organization"
33894
36376
  }
33895
36377
  }
33896
36378
  }
33897
36379
  },
33898
36380
  "400": {
33899
- "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.",
33900
36382
  "content": {
33901
36383
  "application/json": {
33902
36384
  "schema": {
@@ -33911,7 +36393,7 @@
33911
36393
  "type": "string",
33912
36394
  "enum": [
33913
36395
  "invalid_id",
33914
- "invalid_expand",
36396
+ "already_exists",
33915
36397
  "validation_error"
33916
36398
  ]
33917
36399
  }
@@ -34052,49 +36534,20 @@
34052
36534
  }
34053
36535
  }
34054
36536
  },
34055
- "post": {
34056
- "operationId": "team/update",
34057
- "summary": "Update Team",
36537
+ "delete": {
36538
+ "operationId": "organization/delete",
36539
+ "summary": "Delete Organization",
34058
36540
  "tags": [
34059
- "team"
36541
+ "organization"
34060
36542
  ],
34061
- "description": "Update Team",
34062
- "requestBody": {
34063
- "required": true,
34064
- "content": {
34065
- "application/json": {
34066
- "schema": {
34067
- "type": "object",
34068
- "properties": {
34069
- "name": {
34070
- "type": "string",
34071
- "description": "New human-readable name for the team."
34072
- },
34073
- "description": {
34074
- "type": "string",
34075
- "description": "New free-form description for the team."
34076
- },
34077
- "metadata": {
34078
- "type": "object",
34079
- "properties": {},
34080
- "additionalProperties": true,
34081
- "description": "Arbitrary key/value pairs attached to the team. Replaces the previous metadata entirely."
34082
- }
34083
- },
34084
- "description": "Partial update for a Team. Only the supplied fields are modified. `slug` is auto-derived from `name` and is not user-editable.",
34085
- "additionalProperties": false
34086
- }
34087
- }
34088
- },
34089
- "description": "Partial update for a Team. Only the supplied fields are modified. `slug` is auto-derived from `name` and is not user-editable."
34090
- },
36543
+ "description": "Delete Organization",
34091
36544
  "parameters": [
34092
36545
  {
34093
36546
  "schema": {
34094
36547
  "type": "string"
34095
36548
  },
34096
36549
  "in": "path",
34097
- "name": "team_id",
36550
+ "name": "organization_id",
34098
36551
  "required": true
34099
36552
  }
34100
36553
  ],
@@ -34105,7 +36558,7 @@
34105
36558
  ],
34106
36559
  "responses": {
34107
36560
  "200": {
34108
- "description": "Team",
36561
+ "description": "Organization",
34109
36562
  "content": {
34110
36563
  "application/json": {
34111
36564
  "schema": {
@@ -34116,34 +36569,42 @@
34116
36569
  "slug",
34117
36570
  "description",
34118
36571
  "logo_url",
36572
+ "admins",
34119
36573
  "account",
34120
36574
  "createdAt"
34121
36575
  ],
34122
36576
  "properties": {
34123
36577
  "id": {
34124
36578
  "type": "string",
34125
- "description": "Team ID"
36579
+ "description": "Organization ID"
34126
36580
  },
34127
36581
  "name": {
34128
36582
  "type": "string",
34129
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34130
- "example": "Acme Engineering"
36583
+ "description": "Human-readable name of the organization.",
36584
+ "example": "Acme Inc."
34131
36585
  },
34132
36586
  "slug": {
34133
36587
  "type": "string",
34134
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34135
- "example": "acme-engineering"
36588
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
36589
+ "example": "acme-inc"
34136
36590
  },
34137
36591
  "description": {
34138
36592
  "type": "string",
34139
- "description": "Optional free-form description of the team.",
36593
+ "description": "Optional free-form description.",
34140
36594
  "nullable": true
34141
36595
  },
34142
36596
  "logo_url": {
34143
36597
  "type": "string",
34144
- "description": "Optional URL of an image used as the team avatar/logo.",
36598
+ "description": "Optional URL of the organization logo.",
34145
36599
  "nullable": true
34146
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
+ },
34147
36608
  "account": {
34148
36609
  "type": "string",
34149
36610
  "description": "Object is related with this account"
@@ -34152,25 +36613,25 @@
34152
36613
  "type": "object",
34153
36614
  "properties": {},
34154
36615
  "additionalProperties": true,
34155
- "description": "TeamMetadata",
36616
+ "description": "OrganizationMetadata",
34156
36617
  "default": {}
34157
36618
  },
34158
36619
  "createdAt": {
34159
36620
  "type": "string",
34160
- "description": "Team creation date"
36621
+ "description": "Organization creation date"
34161
36622
  },
34162
36623
  "updatedAt": {
34163
36624
  "type": "string",
34164
- "description": "Team updated date"
36625
+ "description": "Organization updated date"
34165
36626
  }
34166
36627
  },
34167
- "description": "Team"
36628
+ "description": "Organization"
34168
36629
  }
34169
36630
  }
34170
36631
  }
34171
36632
  },
34172
36633
  "400": {
34173
- "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.",
34174
36635
  "content": {
34175
36636
  "application/json": {
34176
36637
  "schema": {
@@ -34185,7 +36646,6 @@
34185
36646
  "type": "string",
34186
36647
  "enum": [
34187
36648
  "invalid_id",
34188
- "already_exists",
34189
36649
  "validation_error"
34190
36650
  ]
34191
36651
  }
@@ -34325,21 +36785,44 @@
34325
36785
  }
34326
36786
  }
34327
36787
  }
34328
- },
34329
- "delete": {
34330
- "operationId": "team/delete",
34331
- "summary": "Delete Team",
36788
+ }
36789
+ },
36790
+ "/organization/{organization_id}/admin": {
36791
+ "post": {
36792
+ "operationId": "organization/addAdmin",
36793
+ "summary": "Add an admin to an Organization",
34332
36794
  "tags": [
34333
- "team"
36795
+ "organization"
34334
36796
  ],
34335
- "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
+ },
34336
36819
  "parameters": [
34337
36820
  {
34338
36821
  "schema": {
34339
36822
  "type": "string"
34340
36823
  },
34341
36824
  "in": "path",
34342
- "name": "team_id",
36825
+ "name": "organization_id",
34343
36826
  "required": true
34344
36827
  }
34345
36828
  ],
@@ -34350,7 +36833,7 @@
34350
36833
  ],
34351
36834
  "responses": {
34352
36835
  "200": {
34353
- "description": "Team",
36836
+ "description": "Organization",
34354
36837
  "content": {
34355
36838
  "application/json": {
34356
36839
  "schema": {
@@ -34361,34 +36844,42 @@
34361
36844
  "slug",
34362
36845
  "description",
34363
36846
  "logo_url",
36847
+ "admins",
34364
36848
  "account",
34365
36849
  "createdAt"
34366
36850
  ],
34367
36851
  "properties": {
34368
36852
  "id": {
34369
36853
  "type": "string",
34370
- "description": "Team ID"
36854
+ "description": "Organization ID"
34371
36855
  },
34372
36856
  "name": {
34373
36857
  "type": "string",
34374
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34375
- "example": "Acme Engineering"
36858
+ "description": "Human-readable name of the organization.",
36859
+ "example": "Acme Inc."
34376
36860
  },
34377
36861
  "slug": {
34378
36862
  "type": "string",
34379
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34380
- "example": "acme-engineering"
36863
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
36864
+ "example": "acme-inc"
34381
36865
  },
34382
36866
  "description": {
34383
36867
  "type": "string",
34384
- "description": "Optional free-form description of the team.",
36868
+ "description": "Optional free-form description.",
34385
36869
  "nullable": true
34386
36870
  },
34387
36871
  "logo_url": {
34388
36872
  "type": "string",
34389
- "description": "Optional URL of an image used as the team avatar/logo.",
36873
+ "description": "Optional URL of the organization logo.",
34390
36874
  "nullable": true
34391
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
+ },
34392
36883
  "account": {
34393
36884
  "type": "string",
34394
36885
  "description": "Object is related with this account"
@@ -34397,25 +36888,25 @@
34397
36888
  "type": "object",
34398
36889
  "properties": {},
34399
36890
  "additionalProperties": true,
34400
- "description": "TeamMetadata",
36891
+ "description": "OrganizationMetadata",
34401
36892
  "default": {}
34402
36893
  },
34403
36894
  "createdAt": {
34404
36895
  "type": "string",
34405
- "description": "Team creation date"
36896
+ "description": "Organization creation date"
34406
36897
  },
34407
36898
  "updatedAt": {
34408
36899
  "type": "string",
34409
- "description": "Team updated date"
36900
+ "description": "Organization updated date"
34410
36901
  }
34411
36902
  },
34412
- "description": "Team"
36903
+ "description": "Organization"
34413
36904
  }
34414
36905
  }
34415
36906
  }
34416
36907
  },
34417
36908
  "400": {
34418
- "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.",
34419
36910
  "content": {
34420
36911
  "application/json": {
34421
36912
  "schema": {
@@ -34429,7 +36920,7 @@
34429
36920
  "error_code": {
34430
36921
  "type": "string",
34431
36922
  "enum": [
34432
- "invalid_id",
36923
+ "invalid_user",
34433
36924
  "validation_error"
34434
36925
  ]
34435
36926
  }
@@ -34493,7 +36984,7 @@
34493
36984
  }
34494
36985
  },
34495
36986
  "404": {
34496
- "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).",
34497
36988
  "content": {
34498
36989
  "application/json": {
34499
36990
  "schema": {
@@ -34507,7 +36998,7 @@
34507
36998
  "error_code": {
34508
36999
  "type": "string",
34509
37000
  "enum": [
34510
- "not_found",
37001
+ "organization_not_found",
34511
37002
  "account_not_found"
34512
37003
  ]
34513
37004
  }
@@ -34569,65 +37060,32 @@
34569
37060
  }
34570
37061
  }
34571
37062
  }
34572
- },
34573
- "put": {
34574
- "operationId": "team/put",
34575
- "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",
34576
37069
  "tags": [
34577
- "team"
37070
+ "organization"
34578
37071
  ],
34579
- "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.",
34580
- "requestBody": {
34581
- "required": true,
34582
- "content": {
34583
- "application/json": {
34584
- "schema": {
34585
- "type": "object",
34586
- "required": [
34587
- "name"
34588
- ],
34589
- "properties": {
34590
- "name": {
34591
- "type": "string",
34592
- "minLength": 1,
34593
- "description": "Human-readable name of the team.",
34594
- "example": "Acme Engineering"
34595
- },
34596
- "slug": {
34597
- "type": "string",
34598
- "minLength": 1,
34599
- "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
34600
- "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.",
34601
- "example": "acme-engineering"
34602
- },
34603
- "description": {
34604
- "type": "string",
34605
- "description": "Optional free-form description."
34606
- },
34607
- "metadata": {
34608
- "type": "object",
34609
- "properties": {},
34610
- "additionalProperties": true,
34611
- "description": "Arbitrary key/value pairs attached to the team. Replaces the previous metadata entirely."
34612
- }
34613
- },
34614
- "additionalProperties": false,
34615
- "description": "Payload for creating or updating a Team under a caller-chosen id."
34616
- }
34617
- }
34618
- },
34619
- "description": "Payload for creating or updating a Team under a caller-chosen id."
34620
- },
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`.",
34621
37073
  "parameters": [
34622
37074
  {
34623
37075
  "schema": {
34624
- "type": "string",
34625
- "pattern": "^team_[0-9a-f]{24}$"
37076
+ "type": "string"
34626
37077
  },
34627
37078
  "in": "path",
34628
- "name": "team_id",
34629
- "required": true,
34630
- "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
34631
37089
  }
34632
37090
  ],
34633
37091
  "security": [
@@ -34637,7 +37095,7 @@
34637
37095
  ],
34638
37096
  "responses": {
34639
37097
  "200": {
34640
- "description": "Team",
37098
+ "description": "Organization",
34641
37099
  "content": {
34642
37100
  "application/json": {
34643
37101
  "schema": {
@@ -34648,98 +37106,41 @@
34648
37106
  "slug",
34649
37107
  "description",
34650
37108
  "logo_url",
37109
+ "admins",
34651
37110
  "account",
34652
37111
  "createdAt"
34653
37112
  ],
34654
37113
  "properties": {
34655
37114
  "id": {
34656
37115
  "type": "string",
34657
- "description": "Team ID"
37116
+ "description": "Organization ID"
34658
37117
  },
34659
37118
  "name": {
34660
37119
  "type": "string",
34661
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34662
- "example": "Acme Engineering"
37120
+ "description": "Human-readable name of the organization.",
37121
+ "example": "Acme Inc."
34663
37122
  },
34664
37123
  "slug": {
34665
37124
  "type": "string",
34666
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34667
- "example": "acme-engineering"
37125
+ "description": "URL-safe identifier derived from `name`. Unique within the tenant.",
37126
+ "example": "acme-inc"
34668
37127
  },
34669
37128
  "description": {
34670
37129
  "type": "string",
34671
- "description": "Optional free-form description of the team.",
37130
+ "description": "Optional free-form description.",
34672
37131
  "nullable": true
34673
37132
  },
34674
37133
  "logo_url": {
34675
37134
  "type": "string",
34676
- "description": "Optional URL of an image used as the team avatar/logo.",
34677
- "nullable": true
34678
- },
34679
- "account": {
34680
- "type": "string",
34681
- "description": "Object is related with this account"
34682
- },
34683
- "metadata": {
34684
- "type": "object",
34685
- "properties": {},
34686
- "additionalProperties": true,
34687
- "description": "TeamMetadata",
34688
- "default": {}
34689
- },
34690
- "createdAt": {
34691
- "type": "string",
34692
- "description": "Team creation date"
34693
- },
34694
- "updatedAt": {
34695
- "type": "string",
34696
- "description": "Team updated date"
34697
- }
34698
- },
34699
- "description": "Team"
34700
- }
34701
- }
34702
- }
34703
- },
34704
- "201": {
34705
- "description": "Team",
34706
- "content": {
34707
- "application/json": {
34708
- "schema": {
34709
- "type": "object",
34710
- "required": [
34711
- "id",
34712
- "name",
34713
- "slug",
34714
- "description",
34715
- "logo_url",
34716
- "account",
34717
- "createdAt"
34718
- ],
34719
- "properties": {
34720
- "id": {
34721
- "type": "string",
34722
- "description": "Team ID"
34723
- },
34724
- "name": {
34725
- "type": "string",
34726
- "description": "Human-readable name of the team. Shown in the dashboard and in team-picker UI.",
34727
- "example": "Acme Engineering"
34728
- },
34729
- "slug": {
34730
- "type": "string",
34731
- "description": "URL-safe identifier auto-derived from `name`. Unique within the tenant; used in routes that address a team by slug.",
34732
- "example": "acme-engineering"
34733
- },
34734
- "description": {
34735
- "type": "string",
34736
- "description": "Optional free-form description of the team.",
37135
+ "description": "Optional URL of the organization logo.",
34737
37136
  "nullable": true
34738
37137
  },
34739
- "logo_url": {
34740
- "type": "string",
34741
- "description": "Optional URL of an image used as the team avatar/logo.",
34742
- "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."
34743
37144
  },
34744
37145
  "account": {
34745
37146
  "type": "string",
@@ -34749,25 +37150,25 @@
34749
37150
  "type": "object",
34750
37151
  "properties": {},
34751
37152
  "additionalProperties": true,
34752
- "description": "TeamMetadata",
37153
+ "description": "OrganizationMetadata",
34753
37154
  "default": {}
34754
37155
  },
34755
37156
  "createdAt": {
34756
37157
  "type": "string",
34757
- "description": "Team creation date"
37158
+ "description": "Organization creation date"
34758
37159
  },
34759
37160
  "updatedAt": {
34760
37161
  "type": "string",
34761
- "description": "Team updated date"
37162
+ "description": "Organization updated date"
34762
37163
  }
34763
37164
  },
34764
- "description": "Team"
37165
+ "description": "Organization"
34765
37166
  }
34766
37167
  }
34767
37168
  }
34768
37169
  },
34769
37170
  "400": {
34770
- "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.",
34771
37172
  "content": {
34772
37173
  "application/json": {
34773
37174
  "schema": {
@@ -34781,7 +37182,6 @@
34781
37182
  "error_code": {
34782
37183
  "type": "string",
34783
37184
  "enum": [
34784
- "already_exists",
34785
37185
  "validation_error"
34786
37186
  ]
34787
37187
  }
@@ -34845,7 +37245,7 @@
34845
37245
  }
34846
37246
  },
34847
37247
  "404": {
34848
- "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).",
34849
37249
  "content": {
34850
37250
  "application/json": {
34851
37251
  "schema": {
@@ -34859,6 +37259,8 @@
34859
37259
  "error_code": {
34860
37260
  "type": "string",
34861
37261
  "enum": [
37262
+ "organization_not_found",
37263
+ "not_an_organization_admin",
34862
37264
  "account_not_found"
34863
37265
  ]
34864
37266
  }
@@ -34870,7 +37272,7 @@
34870
37272
  }
34871
37273
  },
34872
37274
  "409": {
34873
- "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.",
34874
37276
  "content": {
34875
37277
  "application/json": {
34876
37278
  "schema": {
@@ -34884,7 +37286,7 @@
34884
37286
  "error_code": {
34885
37287
  "type": "string",
34886
37288
  "enum": [
34887
- "team_id_unavailable"
37289
+ "last_organization_admin"
34888
37290
  ]
34889
37291
  }
34890
37292
  }
@@ -49841,7 +52243,7 @@
49841
52243
  "items": {
49842
52244
  "type": "string"
49843
52245
  },
49844
- "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."
49845
52247
  },
49846
52248
  "channel": {
49847
52249
  "type": "string",
@@ -49994,7 +52396,7 @@
49994
52396
  "items": {
49995
52397
  "type": "string"
49996
52398
  },
49997
- "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."
49998
52400
  },
49999
52401
  "channel": {
50000
52402
  "type": "string",
@@ -50364,7 +52766,7 @@
50364
52766
  "items": {
50365
52767
  "type": "string"
50366
52768
  },
50367
- "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."
50368
52770
  },
50369
52771
  "channel": {
50370
52772
  "type": "string",
@@ -50674,7 +53076,7 @@
50674
53076
  "items": {
50675
53077
  "type": "string"
50676
53078
  },
50677
- "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."
50678
53080
  },
50679
53081
  "channel": {
50680
53082
  "type": "string",
@@ -50831,7 +53233,7 @@
50831
53233
  "items": {
50832
53234
  "type": "string"
50833
53235
  },
50834
- "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."
50835
53237
  },
50836
53238
  "channel": {
50837
53239
  "type": "string",
@@ -51201,7 +53603,7 @@
51201
53603
  "items": {
51202
53604
  "type": "string"
51203
53605
  },
51204
- "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."
51205
53607
  },
51206
53608
  "channel": {
51207
53609
  "type": "string",
@@ -62389,6 +64791,15 @@
62389
64791
  "name": "resource",
62390
64792
  "required": false,
62391
64793
  "description": "RFC 8707 Resource Indicator. Absolute URI of the target Api, no fragment. Matched against `Api.identifier` in the tenant."
64794
+ },
64795
+ {
64796
+ "schema": {
64797
+ "type": "string"
64798
+ },
64799
+ "in": "query",
64800
+ "name": "invalidate_token",
64801
+ "required": false,
64802
+ "description": "client_credentials only. An access token previously returned by this endpoint that a resource server rejected with 401. If it is the cached token for this client, the cache entry is dropped and a new token is issued; otherwise it has no effect."
62392
64803
  }
62393
64804
  ],
62394
64805
  "responses": {
@@ -62658,6 +65069,10 @@
62658
65069
  "resource": {
62659
65070
  "type": "string",
62660
65071
  "description": "RFC 8707 Resource Indicator. Absolute URI of the target Api, no fragment. Matched against `Api.identifier` in the tenant."
65072
+ },
65073
+ "invalidate_token": {
65074
+ "type": "string",
65075
+ "description": "client_credentials only. An access token previously returned by this endpoint that a resource server rejected with 401. If it is the cached token for this client, the cache entry is dropped and a new token is issued; otherwise it has no effect."
62661
65076
  }
62662
65077
  },
62663
65078
  "additionalProperties": true
@@ -62871,6 +65286,15 @@
62871
65286
  "name": "resource",
62872
65287
  "required": false,
62873
65288
  "description": "RFC 8707 Resource Indicator. Absolute URI of the target Api, no fragment. Matched against `Api.identifier` in the tenant."
65289
+ },
65290
+ {
65291
+ "schema": {
65292
+ "type": "string"
65293
+ },
65294
+ "in": "query",
65295
+ "name": "invalidate_token",
65296
+ "required": false,
65297
+ "description": "client_credentials only. An access token previously returned by this endpoint that a resource server rejected with 401. If it is the cached token for this client, the cache entry is dropped and a new token is issued; otherwise it has no effect."
62874
65298
  }
62875
65299
  ],
62876
65300
  "responses": {
@@ -64632,7 +67056,7 @@
64632
67056
  "tags": [
64633
67057
  "oauth"
64634
67058
  ],
64635
- "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).",
64636
67060
  "requestBody": {
64637
67061
  "required": true,
64638
67062
  "content": {
@@ -64900,6 +67324,31 @@
64900
67324
  }
64901
67325
  }
64902
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
+ },
64903
67352
  "404": {
64904
67353
  "description": "`account_not_found` — No Auth Account matches the request (domain, header or token).",
64905
67354
  "content": {