@canopy-io/node 0.5.0 → 0.7.0

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/dist/index.d.cts CHANGED
@@ -514,7 +514,7 @@ interface paths {
514
514
  head?: never;
515
515
  /**
516
516
  * Update an identity
517
- * @description Updates an identity's mutable profile fields (`first_name`, `last_name`, `is_active`, `metadata`) in the current Environment. `email` and `external_id` are immutable here — `external_id` is owned by the SSO/SCIM provisioning path and cannot be re-pointed through this endpoint. Returns the updated identity and writes an `identity.updated` audit row for the profile fields; a change to `is_active` writes `identity.status_set` instead, the account-wide activation switch. Returns `404` when the identity has no membership in this Environment.
517
+ * @description Updates an identity's mutable profile fields (`first_name`, `last_name`, `metadata`) in the current Environment. `email` and `external_id` are immutable here — `external_id` is owned by the SSO/SCIM provisioning path and cannot be re-pointed through this endpoint. The account-wide `is_active` switch is not settable from an Environment; to cut off access here, remove the identity from the Environment. Returns the updated identity and writes an `identity.updated` audit row. Returns `404` when the identity has no membership in this Environment.
518
518
  */
519
519
  patch: operations["ApiIdentitiesController_updateIdentity"];
520
520
  trace?: never;
@@ -539,46 +539,6 @@ interface paths {
539
539
  patch?: never;
540
540
  trace?: never;
541
541
  };
542
- "/api/v1/identities/{id}/activate": {
543
- parameters: {
544
- query?: never;
545
- header?: never;
546
- path?: never;
547
- cookie?: never;
548
- };
549
- get?: never;
550
- put?: never;
551
- /**
552
- * Activate an identity
553
- * @description Reactivates an identity by setting `is_active = true`, the account-wide switch, allowing it to authenticate again in every Environment it belongs to. Writes an `identity.status_set` audit row (the same event the Console's account route emits), delivered to the account's subscriptions and to those of every Environment the identity is a member of. Returns a `200` message envelope. Returns `404` when the identity has no membership in this Environment.
554
- */
555
- post: operations["ApiIdentitiesController_activateIdentity"];
556
- delete?: never;
557
- options?: never;
558
- head?: never;
559
- patch?: never;
560
- trace?: never;
561
- };
562
- "/api/v1/identities/{id}/deactivate": {
563
- parameters: {
564
- query?: never;
565
- header?: never;
566
- path?: never;
567
- cookie?: never;
568
- };
569
- get?: never;
570
- put?: never;
571
- /**
572
- * Deactivate an identity
573
- * @description Deactivates an identity by setting `is_active = false`, the account-wide switch, blocking future sign-in in every Environment it belongs to. Writes an `identity.status_set` audit row (the same event the Console's account route emits), delivered to the account's subscriptions and to those of every Environment the identity is a member of. Returns a `200` message envelope. Returns `404` when the identity has no membership in this Environment.
574
- */
575
- post: operations["ApiIdentitiesController_deactivateIdentity"];
576
- delete?: never;
577
- options?: never;
578
- head?: never;
579
- patch?: never;
580
- trace?: never;
581
- };
582
542
  "/api/v1/identities/{id}/password": {
583
543
  parameters: {
584
544
  query?: never;
@@ -834,7 +794,7 @@ interface paths {
834
794
  put?: never;
835
795
  /**
836
796
  * Create an invite
837
- * @description Creates a single identity invite in the active Environment and returns it along with a tokenized `accept_url`. The effective intent is derived server-side from existing identity state — a net-new email becomes `activate`, an existing identity without active access becomes `add_to_app`, and `password_reset` is honored only for an existing identity. An optional `role_id` + `node_id` pair (both or neither) seeds an initial role assignment applied at acceptance. Invites expire after 7 days; the email is sent unless `send_email: false`, in which case the caller delivers `accept_url` itself. A duplicate pending invite for the same recipient returns `409`.
797
+ * @description Creates a single identity invite in the active Environment and returns it along with a tokenized `accept_url`. The effective intent is derived server-side from existing identity state — a net-new email becomes `activate`, an existing identity without active access becomes `add_to_app`, and `password_reset` is honored only for an existing identity. An optional `role_id` + `node_id` pair (both or neither) seeds an initial role assignment applied at acceptance. Invites expire after 7 days, or 24 hours for `password_reset`; the email is sent unless `send_email: false`, in which case the caller delivers `accept_url` itself. A duplicate pending invite for the same recipient returns `409`.
838
798
  */
839
799
  post: operations["ApiIdentityInvitesController_createInvite"];
840
800
  delete?: never;
@@ -894,7 +854,7 @@ interface paths {
894
854
  put?: never;
895
855
  /**
896
856
  * Resend an invite
897
- * @description Resends the email for a `pending` invite in the active Environment, generating a fresh token, invalidating the previous one, and resetting the 7-day expiry. Returns the new tokenized `accept_url`. Subject to a 5-minute cooldown between resends. Returns `404` when the invite is not found and `400` when it is not in `pending` status or the cooldown has not elapsed.
857
+ * @description Resends the email for a `pending` invite in the active Environment, generating a fresh token, invalidating the previous one, and resetting the expiry (7 days, or 24 hours for `password_reset`). Returns the new tokenized `accept_url`. Subject to a 5-minute cooldown between resends. Returns `404` when the invite is not found and `400` when it is not in `pending` status or the cooldown has not elapsed.
898
858
  */
899
859
  post: operations["ApiIdentityInvitesController_resendInvite"];
900
860
  delete?: never;
@@ -1355,7 +1315,7 @@ interface paths {
1355
1315
  post?: never;
1356
1316
  /**
1357
1317
  * Unbind an SSO connection from an organization
1358
- * @description Removes the binding; logins through the connection fall back to the Environment's placement. Existing memberships are untouched. Returns `404` when the connection is not bound to this organization. Requires the `hierarchy.manage` permission at the organization and emits `organization.sso_connection.unbound`.
1318
+ * @description Removes the binding; logins through the connection fall back to the Environment's placement. Existing memberships are untouched. Returns `404` when the connection is not bound to this organization, and `409` (`organization.sso_connection_owned_cannot_unbind`) when the organization set the connection up itself: an owned connection stays with its organization, so disable or delete it instead. Requires the `hierarchy.manage` permission at the organization and emits `organization.sso_connection.unbound`.
1359
1319
  */
1360
1320
  delete: operations["ApiOrganizationsController_unbindSsoConnection"];
1361
1321
  options?: never;
@@ -1748,7 +1708,7 @@ interface paths {
1748
1708
  };
1749
1709
  /**
1750
1710
  * Recent directory-sync activity for an organization
1751
- * @description The organization's own provisioning events, newest first
1711
+ * @description The organization's own directory events (provisioning, group mapping, and changes to its connection, tokens and allowed roles), newest first
1752
1712
  */
1753
1713
  get: operations["ApiOrganizationDirectoryController_activity"];
1754
1714
  put?: never;
@@ -1874,7 +1834,7 @@ interface paths {
1874
1834
  head?: never;
1875
1835
  /**
1876
1836
  * Update a role
1877
- * @description Updates a role's `name`, `description`, and/or `is_active` flag by `id`. A name that collides with another role in the Environment returns `409`, and a missing role returns `404`. Supports optimistic concurrency via the `If-Match` header carrying the role's current version (`409` on a version mismatch). Requires the `rbac.manage_roles` permission.
1837
+ * @description Updates a role's `name`, `description`, and/or `is_active` flag by `id`. Setting `is_active` to `false` hides the role from pickers, refuses new assignments to it, and withholds its permissions from every current holder until it is set back to `true`; the assignments themselves are kept. A name that collides with another role in the Environment returns `409`, and a missing role returns `404`. Supports optimistic concurrency via the `If-Match` header carrying the role's current version (`409` on a version mismatch). Requires the `rbac.manage_roles` permission.
1878
1838
  */
1879
1839
  patch: operations["ApiRolesController_updateRole"];
1880
1840
  trace?: never;
@@ -2295,6 +2255,98 @@ interface paths {
2295
2255
  patch: operations["ApiWebhooksController_update"];
2296
2256
  trace?: never;
2297
2257
  };
2258
+ "/api/v1/oauth-clients": {
2259
+ parameters: {
2260
+ query?: never;
2261
+ header?: never;
2262
+ path?: never;
2263
+ cookie?: never;
2264
+ };
2265
+ /**
2266
+ * List OAuth clients for Application
2267
+ * @description Returns a paginated list of the OAuth clients registered in the current Environment, newest first by default. Supports `q` to filter by client name and the standard sort/pagination query options. Client secrets are never included.
2268
+ */
2269
+ get: operations["ApiOAuthClientsController_list"];
2270
+ put?: never;
2271
+ /**
2272
+ * Register a new OAuth client
2273
+ * @description Registers a new confidential OAuth client in the current Environment with the given `name`, `redirect_uris`, and optional `scopes` (defaulting to `openid profile email`). Generates the `client_id` and a `client_secret` that is bcrypt-hashed at rest; the raw secret is returned in this response only and is never retrievable again. Responds `201 Created`.
2274
+ */
2275
+ post: operations["ApiOAuthClientsController_create"];
2276
+ delete?: never;
2277
+ options?: never;
2278
+ head?: never;
2279
+ patch?: never;
2280
+ trace?: never;
2281
+ };
2282
+ "/api/v1/oauth-clients/summary": {
2283
+ parameters: {
2284
+ query?: never;
2285
+ header?: never;
2286
+ path?: never;
2287
+ cookie?: never;
2288
+ };
2289
+ /**
2290
+ * Active/inactive OAuth client counts for the environment
2291
+ * @description Returns Environment-wide active and inactive OAuth client counts (not just the current page), optionally narrowed by the same `q` name filter the list endpoint uses. Drives the client stat card.
2292
+ */
2293
+ get: operations["ApiOAuthClientsController_summary"];
2294
+ put?: never;
2295
+ post?: never;
2296
+ delete?: never;
2297
+ options?: never;
2298
+ head?: never;
2299
+ patch?: never;
2300
+ trace?: never;
2301
+ };
2302
+ "/api/v1/oauth-clients/{id}": {
2303
+ parameters: {
2304
+ query?: never;
2305
+ header?: never;
2306
+ path?: never;
2307
+ cookie?: never;
2308
+ };
2309
+ /**
2310
+ * Get OAuth client details
2311
+ * @description Returns a single OAuth client by `id`, scoped to the current Environment — a client that exists in a sibling Environment reads as `404`. The `client_secret` is never included.
2312
+ */
2313
+ get: operations["ApiOAuthClientsController_get"];
2314
+ put?: never;
2315
+ post?: never;
2316
+ /**
2317
+ * Delete OAuth client
2318
+ * @description Deletes an OAuth client from the current Environment by `id`. Responds `204 No Content` on success, or `404` when the client is not found in this Environment.
2319
+ */
2320
+ delete: operations["ApiOAuthClientsController_remove"];
2321
+ options?: never;
2322
+ head?: never;
2323
+ /**
2324
+ * Update OAuth client
2325
+ * @description Updates an OAuth client's mutable fields (`name`, `redirect_uris`, `post_logout_redirect_uris`, `backchannel_logout_uri`, `scopes`, `is_active`, `invite_redirect_url`, `initiate_login_uri`), scoped to the current Environment. Returns the updated client, or `404` when the client is not found in this Environment. The secret is not rotated here.
2326
+ */
2327
+ patch: operations["ApiOAuthClientsController_update"];
2328
+ trace?: never;
2329
+ };
2330
+ "/api/v1/oauth-clients/{id}/rotate-secret": {
2331
+ parameters: {
2332
+ query?: never;
2333
+ header?: never;
2334
+ path?: never;
2335
+ cookie?: never;
2336
+ };
2337
+ get?: never;
2338
+ put?: never;
2339
+ /**
2340
+ * Rotate an OAuth client's secret
2341
+ * @description Rotates the OAuth client's `client_secret`, generating and hashing a new secret and invalidating the old one. The new raw secret is returned in this response only and cannot be retrieved again. Returns `404` when the client is not found in the current Environment.
2342
+ */
2343
+ post: operations["ApiOAuthClientsController_rotateSecret"];
2344
+ delete?: never;
2345
+ options?: never;
2346
+ head?: never;
2347
+ patch?: never;
2348
+ trace?: never;
2349
+ };
2298
2350
  "/api/v1/api-keys": {
2299
2351
  parameters: {
2300
2352
  query?: never;
@@ -2430,6 +2482,7 @@ interface components {
2430
2482
  scope_evaluated: "node" | "app_wide";
2431
2483
  /** @description The hierarchy node the decision was anchored to. Always set for `scope_evaluated: "node"`; always null for `scope_evaluated: "app_wide"` because the answer is org-scoped, not node-scoped. */
2432
2484
  effective_node_id?: string | null;
2485
+ /** @description Ids of the roles whose assignments produced a node-scoped allow. Always empty for `scope_evaluated: "app_wide"`, whose answer is not tied to a node, and for a deny. */
2433
2486
  granting_roles: string[];
2434
2487
  denial_reason?: string | null;
2435
2488
  };
@@ -2464,7 +2517,7 @@ interface components {
2464
2517
  assignment_id: string;
2465
2518
  role_id: string;
2466
2519
  role_name: string;
2467
- /** @description Whether the assignment is within its effective_from/effective_to window right now. */
2520
+ /** @description Whether the assignment counts right now: within its effective_from/effective_to window, and its role is active. An inactive role's assignments are kept but grant nothing. */
2468
2521
  active: boolean;
2469
2522
  effective_from?: string | null;
2470
2523
  effective_to?: string | null;
@@ -2560,11 +2613,13 @@ interface components {
2560
2613
  email: string;
2561
2614
  first_name: string;
2562
2615
  last_name: string;
2563
- /** @description Initial password. 8-64 characters. No composition rules — NIST SP 800-63B aligned. A HaveIBeenPwned breach check runs server-side. The effective policy is published on `GET /v1/identity/auth/config`, so a client can state the rules before submit rather than after. Omit to create a passwordless identity (sign-in via SSO/social or forgot-password reset). */
2616
+ /** @description Initial password. 8-64 characters. No composition rules — NIST SP 800-63B aligned. A HaveIBeenPwned breach check runs server-side. The effective policy is published on `GET /v1/identity/auth/config`, so a client can state the rules before submit rather than after. Omit to create a passwordless identity (sign-in via SSO or a password reset). */
2564
2617
  password?: string;
2565
2618
  external_id?: string;
2566
2619
  metadata?: Record<string, unknown>;
2620
+ /** @description Role for an initial assignment — required if node_id is provided */
2567
2621
  role_id?: string;
2622
+ /** @description Node for an initial assignment — required if role_id is provided */
2568
2623
  node_id?: string;
2569
2624
  };
2570
2625
  BulkCreateIdentitiesDto: {
@@ -2588,13 +2643,9 @@ interface components {
2588
2643
  /** Format: date-time */
2589
2644
  updated_at: string;
2590
2645
  };
2591
- MessageResponseDto: {
2592
- message: string;
2593
- };
2594
2646
  UpdateIdentityDto: {
2595
2647
  first_name?: string;
2596
2648
  last_name?: string;
2597
- is_active?: boolean;
2598
2649
  metadata?: Record<string, unknown> | null;
2599
2650
  };
2600
2651
  SetIdentityPasswordDto: {
@@ -2653,7 +2704,7 @@ interface components {
2653
2704
  email_verified: boolean;
2654
2705
  /** Format: date-time */
2655
2706
  email_verified_at?: string | null;
2656
- /** @description Whether the identity has a usable password. False for passwordless (SSO/social/code-only) identities. */
2707
+ /** @description Whether the identity has a usable password. False for passwordless (SSO or email-code-only) identities. */
2657
2708
  password_set: boolean;
2658
2709
  /** @description True while the identity is in an active failed-login lockout window. */
2659
2710
  locked: boolean;
@@ -2706,10 +2757,6 @@ interface components {
2706
2757
  name: string;
2707
2758
  role_id?: string | null;
2708
2759
  node_id?: string | null;
2709
- /** @description Environment the invite targets, or null for a directory-only (account-tier) invite created with the Environment field left empty. */
2710
- environment_id?: string | null;
2711
- /** @description Display name of the target Environment, or null for a directory-only invite. */
2712
- environment_name?: string | null;
2713
2760
  has_initial_assignment: boolean;
2714
2761
  /** @enum {string} */
2715
2762
  status: "pending" | "accepted" | "revoked" | "expired";
@@ -2741,10 +2788,6 @@ interface components {
2741
2788
  name: string;
2742
2789
  role_id?: string | null;
2743
2790
  node_id?: string | null;
2744
- /** @description Environment the invite targets, or null for a directory-only (account-tier) invite created with the Environment field left empty. */
2745
- environment_id?: string | null;
2746
- /** @description Display name of the target Environment, or null for a directory-only invite. */
2747
- environment_name?: string | null;
2748
2791
  has_initial_assignment: boolean;
2749
2792
  /** @enum {string} */
2750
2793
  status: "pending" | "accepted" | "revoked" | "expired";
@@ -3106,6 +3149,8 @@ interface components {
3106
3149
  /** @enum {string} */
3107
3150
  type: "saml" | "oidc";
3108
3151
  status: string;
3152
+ /** @description The organization that set the connection up from the organization portal, or null. A connection owned by this organization cannot be unbound from it. */
3153
+ owner_organization_node_id?: string | null;
3109
3154
  };
3110
3155
  OrganizationSsoRoleSummaryDto: {
3111
3156
  id: string;
@@ -3228,7 +3273,11 @@ interface components {
3228
3273
  type: "saml" | "oidc";
3229
3274
  name: string;
3230
3275
  /** @enum {string} */
3231
- status: "configuring" | "active" | "disabled" | "failed";
3276
+ status: "configuring" | "active" | "disabled";
3277
+ /** @description The organization that owns the connection, when its administrator set it up from the organization portal; null for a connection the developer created. An owned connection cannot be moved to another organization or Environment, and its administrators are emailed when the developer changes its provider settings, disables or deletes it. */
3278
+ owner_organization_node_id?: string | null;
3279
+ /** @description True when an organization's administrator set the connection up from the organization portal. */
3280
+ owned_by_organization: boolean;
3232
3281
  /** @description The HTTPS address the identity provider's SAML metadata was last imported from. `null` when the metadata was pasted as a document or never imported. */
3233
3282
  saml_metadata_url?: string | null;
3234
3283
  /** @description The last test sign-in run against the connection. Cleared when its provider settings change, since a test no longer proves them. */
@@ -3253,11 +3302,6 @@ interface components {
3253
3302
  /** Format: date-time */
3254
3303
  last_login_at?: string | null;
3255
3304
  /** Format: date-time */
3256
- last_login_failure_at?: string | null;
3257
- consecutive_failures: number;
3258
- /** Format: date-time */
3259
- auto_disabled_at?: string | null;
3260
- /** Format: date-time */
3261
3305
  created_at: string;
3262
3306
  /** Format: date-time */
3263
3307
  updated_at: string;
@@ -3311,6 +3355,7 @@ interface components {
3311
3355
  saml_name_id_format?: string;
3312
3356
  /** @description Force the IdP to re-authenticate the user on every login (SAML ForceAuthn / OIDC max_age=0). Prevents silent reuse of a stale IdP session on shared devices. */
3313
3357
  force_authn?: boolean;
3358
+ /** @description The identity provider's OIDC discovery document. Canopy's servers fetch it, so it must be an `https` address on a public host; private, loopback and link-local addresses are refused. */
3314
3359
  oidc_discovery_url?: string;
3315
3360
  oidc_client_id?: string;
3316
3361
  /** @description OIDC client secret (plaintext in; encrypted at rest). */
@@ -3336,6 +3381,7 @@ interface components {
3336
3381
  saml_name_id_format?: string;
3337
3382
  /** @description Force the IdP to re-authenticate the user on every login (SAML ForceAuthn / OIDC max_age=0). Prevents silent reuse of a stale IdP session on shared devices. */
3338
3383
  force_authn?: boolean;
3384
+ /** @description The identity provider's OIDC discovery document. Canopy's servers fetch it, so it must be an `https` address on a public host; private, loopback and link-local addresses are refused. */
3339
3385
  oidc_discovery_url?: string;
3340
3386
  oidc_client_id?: string;
3341
3387
  /** @description OIDC client secret (plaintext in; encrypted at rest). */
@@ -3491,9 +3537,12 @@ interface components {
3491
3537
  name?: string;
3492
3538
  /** @description Updated role description */
3493
3539
  description?: string | null;
3494
- /** @description Whether the role is active */
3540
+ /** @description Whether the role is active. An inactive role is hidden from pickers, cannot be newly assigned, and grants nothing to its current holders until it is reactivated; their assignments are kept. */
3495
3541
  is_active?: boolean;
3496
3542
  };
3543
+ MessageResponseDto: {
3544
+ message: string;
3545
+ };
3497
3546
  SetRolePermissionsDto: {
3498
3547
  permission_keys: string[];
3499
3548
  };
@@ -3736,7 +3785,7 @@ interface components {
3736
3785
  /** @description Allowed node types (e.g. ['region', 'district', 'team']). Order is informational, not structural — parent/child rules are governed by `allowed_children`. Names starting with `canopy:` are reserved; with organizations enabled the list starts with `canopy:organization`. */
3737
3786
  node_types: string[];
3738
3787
  /**
3739
- * @description Map from node type to allowed child node types. Empty array means leaf-only.
3788
+ * @description Map from node type to allowed child node types. An empty array makes that type a leaf: nothing may be created or moved beneath it. A type the map does not mention accepts any child.
3740
3789
  * @example {
3741
3790
  * "region": [
3742
3791
  * "district"
@@ -3795,7 +3844,7 @@ interface components {
3795
3844
  UpdateEnvironmentBrandingDto: {
3796
3845
  /** @description The product name hosted pages and the organization admin portal show: in the browser tab title, beside the logo when `logo_kind` is `icon`, as a full logo's alt text, and in place of a logo when none is set. Null clears it, and the pages then show no name. */
3797
3846
  product_name?: string | null;
3798
- /** @description Absolute https URL of the logo shown at the top of hosted pages and the portal. Null clears it. */
3847
+ /** @description Absolute https URL of the logo shown at the top of hosted pages, the portal and emails to the Environment's users. Emails show it only when the image is a PNG, JPEG or GIF, which every email client displays; with any other format they show the product name. Null clears it. */
3799
3848
  logo_url?: string | null;
3800
3849
  /**
3801
3850
  * @description What the logo image is. `full`: a complete logo that already carries the product name, shown alone. `icon`: a square mark, shown at icon size with the product name beside it. Null returns to `full`.
@@ -3896,6 +3945,90 @@ interface components {
3896
3945
  description?: string | null;
3897
3946
  is_active?: boolean;
3898
3947
  };
3948
+ OAuthClientCreatedResponseDto: {
3949
+ id: string;
3950
+ client_id: string;
3951
+ name: string;
3952
+ redirect_uris: string[];
3953
+ /** @description Where this client may send someone after RP-initiated logout, matched exactly. */
3954
+ post_logout_redirect_uris: string[];
3955
+ grant_types: string[];
3956
+ scopes: string[];
3957
+ /** @description Where Canopy delivers a logout token when a session ends. Null means the client is told nothing. */
3958
+ backchannel_logout_uri?: string | null;
3959
+ invite_redirect_url?: string | null;
3960
+ /** @description The route in the client's application that starts a sign-in (OpenID Connect `initiate_login_uri`), offered as **Sign in** on hosted pages that end with nothing to return to. */
3961
+ initiate_login_uri?: string | null;
3962
+ is_active: boolean;
3963
+ /** Format: date-time */
3964
+ created_at: string;
3965
+ /**
3966
+ * @description The issuer this client's tokens name, which a relying party configures: `https://<custom auth domain>` while the Environment has an active one, else the platform's. Its discovery document is at `<issuer>/.well-known/openid-configuration`.
3967
+ * @example https://auth.yourapp.com
3968
+ */
3969
+ issuer: string;
3970
+ /** @description Client secret — shown only once */
3971
+ client_secret: string;
3972
+ };
3973
+ CreateOAuthClientDto: {
3974
+ name: string;
3975
+ redirect_uris: string[];
3976
+ /** @description Where this client may send someone after RP-initiated logout. Matched exactly, and separate from `redirect_uris`: receiving an authorization code and being a landing page after sign-out are different kinds of trust. */
3977
+ post_logout_redirect_uris?: string[];
3978
+ scopes?: string[];
3979
+ /** @description Where Canopy delivers a signed logout token, server to server, when a session this client issued tokens for ends. Omit it and the client is told nothing. */
3980
+ backchannel_logout_uri?: string;
3981
+ invite_redirect_url?: string;
3982
+ /** @description The route in your application that starts a sign-in (OpenID Connect `initiate_login_uri`): it should send the person to Canopy's `/oauth/authorize`. Canopy's hosted pages that end with nothing to return to, such as an accepted invitation or a verified email, offer it as **Sign in**. Absolute `http` or `https` URL. */
3983
+ initiate_login_uri?: string;
3984
+ };
3985
+ OAuthClientResponseDto: {
3986
+ id: string;
3987
+ client_id: string;
3988
+ name: string;
3989
+ redirect_uris: string[];
3990
+ /** @description Where this client may send someone after RP-initiated logout, matched exactly. */
3991
+ post_logout_redirect_uris: string[];
3992
+ grant_types: string[];
3993
+ scopes: string[];
3994
+ /** @description Where Canopy delivers a logout token when a session ends. Null means the client is told nothing. */
3995
+ backchannel_logout_uri?: string | null;
3996
+ invite_redirect_url?: string | null;
3997
+ /** @description The route in the client's application that starts a sign-in (OpenID Connect `initiate_login_uri`), offered as **Sign in** on hosted pages that end with nothing to return to. */
3998
+ initiate_login_uri?: string | null;
3999
+ is_active: boolean;
4000
+ /** Format: date-time */
4001
+ created_at: string;
4002
+ /**
4003
+ * @description The issuer this client's tokens name, which a relying party configures: `https://<custom auth domain>` while the Environment has an active one, else the platform's. Its discovery document is at `<issuer>/.well-known/openid-configuration`.
4004
+ * @example https://auth.yourapp.com
4005
+ */
4006
+ issuer: string;
4007
+ };
4008
+ ActiveSummaryDto: {
4009
+ /** @description Active items in the environment */
4010
+ active_count: number;
4011
+ /** @description Inactive items in the environment */
4012
+ inactive_count: number;
4013
+ };
4014
+ UpdateOAuthClientDto: {
4015
+ name?: string;
4016
+ redirect_uris?: string[];
4017
+ /** @description Where this client may send someone after RP-initiated logout. Matched exactly. An empty array removes every destination, which leaves logout working with nowhere to return to. */
4018
+ post_logout_redirect_uris?: string[];
4019
+ scopes?: string[];
4020
+ is_active?: boolean;
4021
+ /** @description Where Canopy delivers a signed logout token when a session this client issued tokens for ends. `null` stops the notifications. */
4022
+ backchannel_logout_uri?: string | null;
4023
+ invite_redirect_url?: string | null;
4024
+ /** @description The route in your application that starts a sign-in (OpenID Connect `initiate_login_uri`): it should send the person to Canopy's `/oauth/authorize`. Canopy's hosted pages that end with nothing to return to, such as an accepted invitation or a verified email, offer it as **Sign in**. Absolute `http` or `https` URL; `null` clears it. */
4025
+ initiate_login_uri?: string | null;
4026
+ };
4027
+ OAuthClientSecretRotatedResponseDto: {
4028
+ client_id: string;
4029
+ /** @description New client secret — shown only once */
4030
+ client_secret: string;
4031
+ };
3899
4032
  ApiKeyCreatedResponseDto: {
3900
4033
  id: string;
3901
4034
  name: string;
@@ -3925,7 +4058,7 @@ interface components {
3925
4058
  */
3926
4059
  access_mode: "scoped" | "full_access";
3927
4060
  /** @description Permission scopes this key is authorized for, each one the platform offers (`GET .../api-keys/scopes`). Required and must be non-empty when `access_mode` is `scoped`. Must be omitted when `access_mode` is `full_access`. */
3928
- scopes?: ("hierarchy.view" | "hierarchy.manage" | "rbac.view_roles" | "rbac.manage_roles" | "rbac.view_assignments" | "rbac.manage_assignments" | "permissions.evaluate" | "identity.view" | "identity.manage" | "api_key.view" | "api_key.manage" | "webhook.view" | "webhook.manage")[];
4061
+ scopes?: ("hierarchy.view" | "hierarchy.manage" | "rbac.view_roles" | "rbac.manage_roles" | "rbac.view_assignments" | "rbac.manage_assignments" | "permissions.evaluate" | "identity.view" | "identity.manage" | "api_key.view" | "api_key.manage" | "webhook.view" | "webhook.manage" | "oauth_client.view" | "oauth_client.manage")[];
3929
4062
  /** @description Expiration date (ISO 8601). Omit for no expiration. */
3930
4063
  expires_at?: string;
3931
4064
  };
@@ -3985,6 +4118,11 @@ interface components {
3985
4118
  * @example GET
3986
4119
  */
3987
4120
  method: string;
4121
+ /**
4122
+ * @description The request's correlation id, the same value as the `X-Correlation-Id` response header. Quote it to support: it finds this exact request in Canopy's logs and error reports.
4123
+ * @example 6d7f2c8e-2f0b-4d0f-9b0e-2b0b2b0b2b0b
4124
+ */
4125
+ correlation_id: string | null;
3988
4126
  /**
3989
4127
  * @description Field-level validation messages, present only on 400 responses from request-body validation.
3990
4128
  * @example [
@@ -6687,6 +6825,27 @@ interface operations {
6687
6825
  "application/json": components["schemas"]["ErrorResponseDto"];
6688
6826
  };
6689
6827
  };
6828
+ /** @description The `Idempotency-Key` was already used by this caller for a request with a different method, path or body. A replay must repeat the original request exactly; a new request takes a new key. */
6829
+ 422: {
6830
+ headers: {
6831
+ [name: string]: unknown;
6832
+ };
6833
+ content: {
6834
+ /**
6835
+ * @example {
6836
+ * "error": {
6837
+ * "statusCode": 422,
6838
+ * "code": null,
6839
+ * "message": "The `Idempotency-Key` was already used by this caller for a request with a different method, path or body. A replay must repeat the original request exactly; a new request takes a new key.",
6840
+ * "timestamp": "2026-04-20T12:00:00.000Z",
6841
+ * "path": "/api/v1/identities/bulk-create",
6842
+ * "method": "POST"
6843
+ * }
6844
+ * }
6845
+ */
6846
+ "application/json": components["schemas"]["ErrorResponseDto"];
6847
+ };
6848
+ };
6690
6849
  };
6691
6850
  };
6692
6851
  ApiIdentitiesController_getIdentity: {
@@ -7121,7 +7280,7 @@ interface operations {
7121
7280
  };
7122
7281
  };
7123
7282
  };
7124
- ApiIdentitiesController_activateIdentity: {
7283
+ ApiIdentitiesController_setIdentityPassword: {
7125
7284
  parameters: {
7126
7285
  query?: never;
7127
7286
  header?: never;
@@ -7130,20 +7289,20 @@ interface operations {
7130
7289
  };
7131
7290
  cookie?: never;
7132
7291
  };
7133
- requestBody?: never;
7292
+ requestBody: {
7293
+ content: {
7294
+ "application/json": components["schemas"]["SetIdentityPasswordDto"];
7295
+ };
7296
+ };
7134
7297
  responses: {
7135
- /** @description Identity activated */
7136
- 200: {
7298
+ /** @description Password set. The identity's existing sessions are revoked and any active failed-login lockout is cleared; the new password takes effect on next sign-in. Intended for backend/admin tooling (e.g. migrating users off a legacy store). */
7299
+ 204: {
7137
7300
  headers: {
7138
7301
  [name: string]: unknown;
7139
7302
  };
7140
- content: {
7141
- "application/json": {
7142
- data: components["schemas"]["MessageResponseDto"];
7143
- };
7144
- };
7303
+ content?: never;
7145
7304
  };
7146
- /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header */
7305
+ /** @description The request failed validation, or the password appears in a known data breach (HaveIBeenPwned check); or the request sent both an `X-API-Key` and an `Authorization` header */
7147
7306
  400: {
7148
7307
  headers: {
7149
7308
  [name: string]: unknown;
@@ -7154,9 +7313,9 @@ interface operations {
7154
7313
  * "error": {
7155
7314
  * "statusCode": 400,
7156
7315
  * "code": null,
7157
- * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
7316
+ * "message": "The request failed validation, or the password appears in a known data breach (HaveIBeenPwned check); or the request sent both an `X-API-Key` and an `Authorization` header",
7158
7317
  * "timestamp": "2026-04-20T12:00:00.000Z",
7159
- * "path": "/api/v1/identities/{id}/activate",
7318
+ * "path": "/api/v1/identities/{id}/password",
7160
7319
  * "method": "POST"
7161
7320
  * }
7162
7321
  * }
@@ -7219,7 +7378,7 @@ interface operations {
7219
7378
  * "code": null,
7220
7379
  * "message": "Identity not found",
7221
7380
  * "timestamp": "2026-04-20T12:00:00.000Z",
7222
- * "path": "/api/v1/identities/{id}/activate",
7381
+ * "path": "/api/v1/identities/{id}/password",
7223
7382
  * "method": "POST"
7224
7383
  * }
7225
7384
  * }
@@ -7229,7 +7388,7 @@ interface operations {
7229
7388
  };
7230
7389
  };
7231
7390
  };
7232
- ApiIdentitiesController_deactivateIdentity: {
7391
+ ApiIdentitiesController_forceResetIdentityPassword: {
7233
7392
  parameters: {
7234
7393
  query?: never;
7235
7394
  header?: never;
@@ -7240,16 +7399,12 @@ interface operations {
7240
7399
  };
7241
7400
  requestBody?: never;
7242
7401
  responses: {
7243
- /** @description Identity deactivated */
7244
- 200: {
7402
+ /** @description A password-reset email is sent so the identity can choose a new password. The current password and existing sessions stay valid until the reset link is used (completing the reset then rotates the password and revokes sessions). For an immediate hard cut, use the revoke-sessions endpoint; to rotate the password outright, use set-password. */
7403
+ 204: {
7245
7404
  headers: {
7246
7405
  [name: string]: unknown;
7247
7406
  };
7248
- content: {
7249
- "application/json": {
7250
- data: components["schemas"]["MessageResponseDto"];
7251
- };
7252
- };
7407
+ content?: never;
7253
7408
  };
7254
7409
  /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header */
7255
7410
  400: {
@@ -7264,7 +7419,7 @@ interface operations {
7264
7419
  * "code": null,
7265
7420
  * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
7266
7421
  * "timestamp": "2026-04-20T12:00:00.000Z",
7267
- * "path": "/api/v1/identities/{id}/deactivate",
7422
+ * "path": "/api/v1/identities/{id}/password/reset",
7268
7423
  * "method": "POST"
7269
7424
  * }
7270
7425
  * }
@@ -7327,7 +7482,7 @@ interface operations {
7327
7482
  * "code": null,
7328
7483
  * "message": "Identity not found",
7329
7484
  * "timestamp": "2026-04-20T12:00:00.000Z",
7330
- * "path": "/api/v1/identities/{id}/deactivate",
7485
+ * "path": "/api/v1/identities/{id}/password/reset",
7331
7486
  * "method": "POST"
7332
7487
  * }
7333
7488
  * }
@@ -7337,7 +7492,7 @@ interface operations {
7337
7492
  };
7338
7493
  };
7339
7494
  };
7340
- ApiIdentitiesController_setIdentityPassword: {
7495
+ ApiIdentitiesController_listIdentitySessions: {
7341
7496
  parameters: {
7342
7497
  query?: never;
7343
7498
  header?: never;
@@ -7346,20 +7501,20 @@ interface operations {
7346
7501
  };
7347
7502
  cookie?: never;
7348
7503
  };
7349
- requestBody: {
7350
- content: {
7351
- "application/json": components["schemas"]["SetIdentityPasswordDto"];
7352
- };
7353
- };
7504
+ requestBody?: never;
7354
7505
  responses: {
7355
- /** @description Password set. The identity's existing sessions are revoked and any active failed-login lockout is cleared; the new password takes effect on next sign-in. Intended for backend/admin tooling (e.g. migrating users off a legacy store). */
7356
- 204: {
7506
+ /** @description Every session the identity holds that is neither revoked nor expired, newest first: the session's current refresh token id (what the per-session revoke takes), when it was signed in and when it expires, the browser's address and user agent, and the organization it is acting in. */
7507
+ 200: {
7357
7508
  headers: {
7358
7509
  [name: string]: unknown;
7359
7510
  };
7360
- content?: never;
7511
+ content: {
7512
+ "application/json": {
7513
+ items: components["schemas"]["IdentitySessionResponseDto"][];
7514
+ };
7515
+ };
7361
7516
  };
7362
- /** @description The request failed validation, or the password appears in a known data breach (HaveIBeenPwned check); or the request sent both an `X-API-Key` and an `Authorization` header */
7517
+ /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header */
7363
7518
  400: {
7364
7519
  headers: {
7365
7520
  [name: string]: unknown;
@@ -7370,10 +7525,10 @@ interface operations {
7370
7525
  * "error": {
7371
7526
  * "statusCode": 400,
7372
7527
  * "code": null,
7373
- * "message": "The request failed validation, or the password appears in a known data breach (HaveIBeenPwned check); or the request sent both an `X-API-Key` and an `Authorization` header",
7528
+ * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
7374
7529
  * "timestamp": "2026-04-20T12:00:00.000Z",
7375
- * "path": "/api/v1/identities/{id}/password",
7376
- * "method": "POST"
7530
+ * "path": "/api/v1/identities/{id}/sessions",
7531
+ * "method": "GET"
7377
7532
  * }
7378
7533
  * }
7379
7534
  */
@@ -7435,8 +7590,8 @@ interface operations {
7435
7590
  * "code": null,
7436
7591
  * "message": "Identity not found",
7437
7592
  * "timestamp": "2026-04-20T12:00:00.000Z",
7438
- * "path": "/api/v1/identities/{id}/password",
7439
- * "method": "POST"
7593
+ * "path": "/api/v1/identities/{id}/sessions",
7594
+ * "method": "GET"
7440
7595
  * }
7441
7596
  * }
7442
7597
  */
@@ -7445,18 +7600,19 @@ interface operations {
7445
7600
  };
7446
7601
  };
7447
7602
  };
7448
- ApiIdentitiesController_forceResetIdentityPassword: {
7603
+ ApiIdentitiesController_revokeIdentitySession: {
7449
7604
  parameters: {
7450
7605
  query?: never;
7451
7606
  header?: never;
7452
7607
  path: {
7453
7608
  id: string;
7609
+ sessionId: string;
7454
7610
  };
7455
7611
  cookie?: never;
7456
7612
  };
7457
7613
  requestBody?: never;
7458
7614
  responses: {
7459
- /** @description A password-reset email is sent so the identity can choose a new password. The current password and existing sessions stay valid until the reset link is used (completing the reset then rotates the password and revokes sessions). For an immediate hard cut, use the revoke-sessions endpoint; to rotate the password outright, use set-password. */
7615
+ /** @description The session's refresh token is revoked, so its next refresh returns 401 while the identity's other sessions carry on. In-flight access tokens keep working until their short TTL expires. */
7460
7616
  204: {
7461
7617
  headers: {
7462
7618
  [name: string]: unknown;
@@ -7476,8 +7632,8 @@ interface operations {
7476
7632
  * "code": null,
7477
7633
  * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
7478
7634
  * "timestamp": "2026-04-20T12:00:00.000Z",
7479
- * "path": "/api/v1/identities/{id}/password/reset",
7480
- * "method": "POST"
7635
+ * "path": "/api/v1/identities/{id}/sessions/{sessionId}",
7636
+ * "method": "DELETE"
7481
7637
  * }
7482
7638
  * }
7483
7639
  */
@@ -7526,7 +7682,7 @@ interface operations {
7526
7682
  "application/json": components["schemas"]["ErrorResponseDto"];
7527
7683
  };
7528
7684
  };
7529
- /** @description Identity not found */
7685
+ /** @description The identity is not found, or the session does not belong to it or is already revoked */
7530
7686
  404: {
7531
7687
  headers: {
7532
7688
  [name: string]: unknown;
@@ -7537,10 +7693,10 @@ interface operations {
7537
7693
  * "error": {
7538
7694
  * "statusCode": 404,
7539
7695
  * "code": null,
7540
- * "message": "Identity not found",
7696
+ * "message": "The identity is not found, or the session does not belong to it or is already revoked",
7541
7697
  * "timestamp": "2026-04-20T12:00:00.000Z",
7542
- * "path": "/api/v1/identities/{id}/password/reset",
7543
- * "method": "POST"
7698
+ * "path": "/api/v1/identities/{id}/sessions/{sessionId}",
7699
+ * "method": "DELETE"
7544
7700
  * }
7545
7701
  * }
7546
7702
  */
@@ -7549,7 +7705,7 @@ interface operations {
7549
7705
  };
7550
7706
  };
7551
7707
  };
7552
- ApiIdentitiesController_listIdentitySessions: {
7708
+ ApiIdentitiesController_revokeIdentitySessions: {
7553
7709
  parameters: {
7554
7710
  query?: never;
7555
7711
  header?: never;
@@ -7560,16 +7716,12 @@ interface operations {
7560
7716
  };
7561
7717
  requestBody?: never;
7562
7718
  responses: {
7563
- /** @description Every session the identity holds that is neither revoked nor expired, newest first: the session's current refresh token id (what the per-session revoke takes), when it was signed in and when it expires, the browser's address and user agent, and the organization it is acting in. */
7564
- 200: {
7719
+ /** @description Every active refresh token for the identity is revoked, so the next refresh on any device returns 401 and the user must sign in again. In-flight access tokens keep working until their short TTL expires. Use as a security-event response (e.g. suspected compromise) from backend tooling. */
7720
+ 204: {
7565
7721
  headers: {
7566
7722
  [name: string]: unknown;
7567
7723
  };
7568
- content: {
7569
- "application/json": {
7570
- items: components["schemas"]["IdentitySessionResponseDto"][];
7571
- };
7572
- };
7724
+ content?: never;
7573
7725
  };
7574
7726
  /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header */
7575
7727
  400: {
@@ -7584,217 +7736,8 @@ interface operations {
7584
7736
  * "code": null,
7585
7737
  * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
7586
7738
  * "timestamp": "2026-04-20T12:00:00.000Z",
7587
- * "path": "/api/v1/identities/{id}/sessions",
7588
- * "method": "GET"
7589
- * }
7590
- * }
7591
- */
7592
- "application/json": components["schemas"]["ErrorResponseDto"];
7593
- };
7594
- };
7595
- /** @description Invalid or expired token */
7596
- 401: {
7597
- headers: {
7598
- [name: string]: unknown;
7599
- };
7600
- content: {
7601
- /**
7602
- * @example {
7603
- * "error": {
7604
- * "statusCode": 401,
7605
- * "code": null,
7606
- * "message": "Invalid or expired token",
7607
- * "timestamp": "2026-04-20T12:00:00.000Z",
7608
- * "path": "/api/v1/identities",
7609
- * "method": "GET"
7610
- * }
7611
- * }
7612
- */
7613
- "application/json": components["schemas"]["ErrorResponseDto"];
7614
- };
7615
- };
7616
- /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
7617
- 403: {
7618
- headers: {
7619
- [name: string]: unknown;
7620
- };
7621
- content: {
7622
- /**
7623
- * @example {
7624
- * "error": {
7625
- * "statusCode": 403,
7626
- * "code": null,
7627
- * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
7628
- * "timestamp": "2026-04-20T12:00:00.000Z",
7629
- * "path": "/api/v1/identities",
7630
- * "method": "GET"
7631
- * }
7632
- * }
7633
- */
7634
- "application/json": components["schemas"]["ErrorResponseDto"];
7635
- };
7636
- };
7637
- /** @description Identity not found */
7638
- 404: {
7639
- headers: {
7640
- [name: string]: unknown;
7641
- };
7642
- content: {
7643
- /**
7644
- * @example {
7645
- * "error": {
7646
- * "statusCode": 404,
7647
- * "code": null,
7648
- * "message": "Identity not found",
7649
- * "timestamp": "2026-04-20T12:00:00.000Z",
7650
- * "path": "/api/v1/identities/{id}/sessions",
7651
- * "method": "GET"
7652
- * }
7653
- * }
7654
- */
7655
- "application/json": components["schemas"]["ErrorResponseDto"];
7656
- };
7657
- };
7658
- };
7659
- };
7660
- ApiIdentitiesController_revokeIdentitySession: {
7661
- parameters: {
7662
- query?: never;
7663
- header?: never;
7664
- path: {
7665
- id: string;
7666
- sessionId: string;
7667
- };
7668
- cookie?: never;
7669
- };
7670
- requestBody?: never;
7671
- responses: {
7672
- /** @description The session's refresh token is revoked, so its next refresh returns 401 while the identity's other sessions carry on. In-flight access tokens keep working until their short TTL expires. */
7673
- 204: {
7674
- headers: {
7675
- [name: string]: unknown;
7676
- };
7677
- content?: never;
7678
- };
7679
- /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header */
7680
- 400: {
7681
- headers: {
7682
- [name: string]: unknown;
7683
- };
7684
- content: {
7685
- /**
7686
- * @example {
7687
- * "error": {
7688
- * "statusCode": 400,
7689
- * "code": null,
7690
- * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
7691
- * "timestamp": "2026-04-20T12:00:00.000Z",
7692
- * "path": "/api/v1/identities/{id}/sessions/{sessionId}",
7693
- * "method": "DELETE"
7694
- * }
7695
- * }
7696
- */
7697
- "application/json": components["schemas"]["ErrorResponseDto"];
7698
- };
7699
- };
7700
- /** @description Invalid or expired token */
7701
- 401: {
7702
- headers: {
7703
- [name: string]: unknown;
7704
- };
7705
- content: {
7706
- /**
7707
- * @example {
7708
- * "error": {
7709
- * "statusCode": 401,
7710
- * "code": null,
7711
- * "message": "Invalid or expired token",
7712
- * "timestamp": "2026-04-20T12:00:00.000Z",
7713
- * "path": "/api/v1/identities",
7714
- * "method": "GET"
7715
- * }
7716
- * }
7717
- */
7718
- "application/json": components["schemas"]["ErrorResponseDto"];
7719
- };
7720
- };
7721
- /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
7722
- 403: {
7723
- headers: {
7724
- [name: string]: unknown;
7725
- };
7726
- content: {
7727
- /**
7728
- * @example {
7729
- * "error": {
7730
- * "statusCode": 403,
7731
- * "code": null,
7732
- * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
7733
- * "timestamp": "2026-04-20T12:00:00.000Z",
7734
- * "path": "/api/v1/identities",
7735
- * "method": "GET"
7736
- * }
7737
- * }
7738
- */
7739
- "application/json": components["schemas"]["ErrorResponseDto"];
7740
- };
7741
- };
7742
- /** @description The identity is not found, or the session does not belong to it or is already revoked */
7743
- 404: {
7744
- headers: {
7745
- [name: string]: unknown;
7746
- };
7747
- content: {
7748
- /**
7749
- * @example {
7750
- * "error": {
7751
- * "statusCode": 404,
7752
- * "code": null,
7753
- * "message": "The identity is not found, or the session does not belong to it or is already revoked",
7754
- * "timestamp": "2026-04-20T12:00:00.000Z",
7755
- * "path": "/api/v1/identities/{id}/sessions/{sessionId}",
7756
- * "method": "DELETE"
7757
- * }
7758
- * }
7759
- */
7760
- "application/json": components["schemas"]["ErrorResponseDto"];
7761
- };
7762
- };
7763
- };
7764
- };
7765
- ApiIdentitiesController_revokeIdentitySessions: {
7766
- parameters: {
7767
- query?: never;
7768
- header?: never;
7769
- path: {
7770
- id: string;
7771
- };
7772
- cookie?: never;
7773
- };
7774
- requestBody?: never;
7775
- responses: {
7776
- /** @description Every active refresh token for the identity is revoked, so the next refresh on any device returns 401 and the user must sign in again. In-flight access tokens keep working until their short TTL expires. Use as a security-event response (e.g. suspected compromise) from backend tooling. */
7777
- 204: {
7778
- headers: {
7779
- [name: string]: unknown;
7780
- };
7781
- content?: never;
7782
- };
7783
- /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header */
7784
- 400: {
7785
- headers: {
7786
- [name: string]: unknown;
7787
- };
7788
- content: {
7789
- /**
7790
- * @example {
7791
- * "error": {
7792
- * "statusCode": 400,
7793
- * "code": null,
7794
- * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
7795
- * "timestamp": "2026-04-20T12:00:00.000Z",
7796
- * "path": "/api/v1/identities/{id}/sessions/revoke",
7797
- * "method": "POST"
7739
+ * "path": "/api/v1/identities/{id}/sessions/revoke",
7740
+ * "method": "POST"
7798
7741
  * }
7799
7742
  * }
7800
7743
  */
@@ -8635,14 +8578,12 @@ interface operations {
8635
8578
  take?: number;
8636
8579
  /** @description Search term */
8637
8580
  q?: string;
8638
- /** @description Column to sort by. Allowed values depend on the endpoint. */
8639
- sort_by?: string;
8581
+ /** @description Column to sort by. Defaults to `created`, newest first. */
8582
+ sort_by?: "name" | "email" | "created";
8640
8583
  /** @description Sort direction */
8641
8584
  order?: "asc" | "desc";
8642
8585
  /** @description Filter by invite status */
8643
8586
  status?: "pending" | "accepted" | "revoked" | "expired";
8644
- /** @description Filter by target Environment. Pass the literal `none` to return only directory-only invites (environment_id is null). */
8645
- environment_id?: string;
8646
8587
  };
8647
8588
  header?: never;
8648
8589
  path?: never;
@@ -9065,6 +9006,27 @@ interface operations {
9065
9006
  "application/json": components["schemas"]["ErrorResponseDto"];
9066
9007
  };
9067
9008
  };
9009
+ /** @description The `Idempotency-Key` was already used by this caller for a request with a different method, path or body. A replay must repeat the original request exactly; a new request takes a new key. */
9010
+ 422: {
9011
+ headers: {
9012
+ [name: string]: unknown;
9013
+ };
9014
+ content: {
9015
+ /**
9016
+ * @example {
9017
+ * "error": {
9018
+ * "statusCode": 422,
9019
+ * "code": null,
9020
+ * "message": "The `Idempotency-Key` was already used by this caller for a request with a different method, path or body. A replay must repeat the original request exactly; a new request takes a new key.",
9021
+ * "timestamp": "2026-04-20T12:00:00.000Z",
9022
+ * "path": "/api/v1/identity-invites/bulk-create",
9023
+ * "method": "POST"
9024
+ * }
9025
+ * }
9026
+ */
9027
+ "application/json": components["schemas"]["ErrorResponseDto"];
9028
+ };
9029
+ };
9068
9030
  };
9069
9031
  };
9070
9032
  ApiIdentityInvitesController_resendInvite: {
@@ -12641,6 +12603,27 @@ interface operations {
12641
12603
  "application/json": components["schemas"]["ErrorResponseDto"];
12642
12604
  };
12643
12605
  };
12606
+ /** @description The organization set this connection up itself; it stays bound. Disable or delete the connection instead. */
12607
+ 409: {
12608
+ headers: {
12609
+ [name: string]: unknown;
12610
+ };
12611
+ content: {
12612
+ /**
12613
+ * @example {
12614
+ * "error": {
12615
+ * "statusCode": 409,
12616
+ * "code": null,
12617
+ * "message": "The organization set this connection up itself; it stays bound. Disable or delete the connection instead.",
12618
+ * "timestamp": "2026-04-20T12:00:00.000Z",
12619
+ * "path": "/api/v1/organizations/{id}/sso-connections/{connectionId}",
12620
+ * "method": "DELETE"
12621
+ * }
12622
+ * }
12623
+ */
12624
+ "application/json": components["schemas"]["ErrorResponseDto"];
12625
+ };
12626
+ };
12644
12627
  };
12645
12628
  };
12646
12629
  ApiOrganizationsController_listMembers: {
@@ -15800,7 +15783,7 @@ interface operations {
15800
15783
  };
15801
15784
  requestBody?: never;
15802
15785
  responses: {
15803
- /** @description The organization's own provisioning events, newest first */
15786
+ /** @description The organization's own directory events (provisioning, group mapping, and changes to its connection, tokens and allowed roles), newest first */
15804
15787
  200: {
15805
15788
  headers: {
15806
15789
  [name: string]: unknown;
@@ -20010,7 +19993,7 @@ interface operations {
20010
19993
  };
20011
19994
  };
20012
19995
  };
20013
- ApiApiKeysController_list: {
19996
+ ApiOAuthClientsController_list: {
20014
19997
  parameters: {
20015
19998
  query?: {
20016
19999
  /** @description Page number (1-based) */
@@ -20037,7 +20020,7 @@ interface operations {
20037
20020
  };
20038
20021
  content: {
20039
20022
  "application/json": {
20040
- items: components["schemas"]["ApiKeyResponseDto"][];
20023
+ items: components["schemas"]["OAuthClientResponseDto"][];
20041
20024
  pagination: components["schemas"]["PageMetaDto"];
20042
20025
  };
20043
20026
  };
@@ -20055,7 +20038,7 @@ interface operations {
20055
20038
  * "code": null,
20056
20039
  * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
20057
20040
  * "timestamp": "2026-04-20T12:00:00.000Z",
20058
- * "path": "/api/v1/api-keys",
20041
+ * "path": "/api/v1/oauth-clients",
20059
20042
  * "method": "GET"
20060
20043
  * }
20061
20044
  * }
@@ -20076,7 +20059,7 @@ interface operations {
20076
20059
  * "code": null,
20077
20060
  * "message": "Invalid or expired token",
20078
20061
  * "timestamp": "2026-04-20T12:00:00.000Z",
20079
- * "path": "/api/v1/api-keys",
20062
+ * "path": "/api/v1/oauth-clients",
20080
20063
  * "method": "GET"
20081
20064
  * }
20082
20065
  * }
@@ -20097,7 +20080,7 @@ interface operations {
20097
20080
  * "code": null,
20098
20081
  * "message": "The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment",
20099
20082
  * "timestamp": "2026-04-20T12:00:00.000Z",
20100
- * "path": "/api/v1/api-keys",
20083
+ * "path": "/api/v1/oauth-clients",
20101
20084
  * "method": "GET"
20102
20085
  * }
20103
20086
  * }
@@ -20107,7 +20090,7 @@ interface operations {
20107
20090
  };
20108
20091
  };
20109
20092
  };
20110
- ApiApiKeysController_create: {
20093
+ ApiOAuthClientsController_create: {
20111
20094
  parameters: {
20112
20095
  query?: never;
20113
20096
  header?: never;
@@ -20116,18 +20099,744 @@ interface operations {
20116
20099
  };
20117
20100
  requestBody: {
20118
20101
  content: {
20119
- "application/json": components["schemas"]["CreateApiKeyDto"];
20102
+ "application/json": components["schemas"]["CreateOAuthClientDto"];
20120
20103
  };
20121
20104
  };
20122
20105
  responses: {
20123
- /** @description API key created — key value is only shown once */
20106
+ /** @description Client created — client_secret is only shown once */
20124
20107
  201: {
20125
20108
  headers: {
20126
20109
  [name: string]: unknown;
20127
20110
  };
20128
20111
  content: {
20129
20112
  "application/json": {
20130
- data: components["schemas"]["ApiKeyCreatedResponseDto"];
20113
+ data: components["schemas"]["OAuthClientCreatedResponseDto"];
20114
+ };
20115
+ };
20116
+ };
20117
+ /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range, `backchannel_logout_uri` names an address Canopy's servers will not call, or `initiate_login_uri` is malformed or not `https` (loopback hosts excepted); or the request sent both an `X-API-Key` and an `Authorization` header */
20118
+ 400: {
20119
+ headers: {
20120
+ [name: string]: unknown;
20121
+ };
20122
+ content: {
20123
+ /**
20124
+ * @example {
20125
+ * "error": {
20126
+ * "statusCode": 400,
20127
+ * "code": null,
20128
+ * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range, `backchannel_logout_uri` names an address Canopy's servers will not call, or `initiate_login_uri` is malformed or not `https` (loopback hosts excepted); or the request sent both an `X-API-Key` and an `Authorization` header",
20129
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20130
+ * "path": "/api/v1/oauth-clients",
20131
+ * "method": "POST"
20132
+ * }
20133
+ * }
20134
+ */
20135
+ "application/json": components["schemas"]["ErrorResponseDto"];
20136
+ };
20137
+ };
20138
+ /** @description Invalid or expired token */
20139
+ 401: {
20140
+ headers: {
20141
+ [name: string]: unknown;
20142
+ };
20143
+ content: {
20144
+ /**
20145
+ * @example {
20146
+ * "error": {
20147
+ * "statusCode": 401,
20148
+ * "code": null,
20149
+ * "message": "Invalid or expired token",
20150
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20151
+ * "path": "/api/v1/oauth-clients",
20152
+ * "method": "GET"
20153
+ * }
20154
+ * }
20155
+ */
20156
+ "application/json": components["schemas"]["ErrorResponseDto"];
20157
+ };
20158
+ };
20159
+ /** @description The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment */
20160
+ 403: {
20161
+ headers: {
20162
+ [name: string]: unknown;
20163
+ };
20164
+ content: {
20165
+ /**
20166
+ * @example {
20167
+ * "error": {
20168
+ * "statusCode": 403,
20169
+ * "code": null,
20170
+ * "message": "The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment",
20171
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20172
+ * "path": "/api/v1/oauth-clients",
20173
+ * "method": "GET"
20174
+ * }
20175
+ * }
20176
+ */
20177
+ "application/json": components["schemas"]["ErrorResponseDto"];
20178
+ };
20179
+ };
20180
+ /** @description The `Idempotency-Key` was already used by this caller for a request with a different method, path or body. A replay must repeat the original request exactly; a new request takes a new key. */
20181
+ 422: {
20182
+ headers: {
20183
+ [name: string]: unknown;
20184
+ };
20185
+ content: {
20186
+ /**
20187
+ * @example {
20188
+ * "error": {
20189
+ * "statusCode": 422,
20190
+ * "code": null,
20191
+ * "message": "The `Idempotency-Key` was already used by this caller for a request with a different method, path or body. A replay must repeat the original request exactly; a new request takes a new key.",
20192
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20193
+ * "path": "/api/v1/oauth-clients",
20194
+ * "method": "POST"
20195
+ * }
20196
+ * }
20197
+ */
20198
+ "application/json": components["schemas"]["ErrorResponseDto"];
20199
+ };
20200
+ };
20201
+ };
20202
+ };
20203
+ ApiOAuthClientsController_summary: {
20204
+ parameters: {
20205
+ query?: {
20206
+ q?: string;
20207
+ };
20208
+ header?: never;
20209
+ path?: never;
20210
+ cookie?: never;
20211
+ };
20212
+ requestBody?: never;
20213
+ responses: {
20214
+ /** @description OAuth client active/inactive summary returned */
20215
+ 200: {
20216
+ headers: {
20217
+ [name: string]: unknown;
20218
+ };
20219
+ content: {
20220
+ "application/json": {
20221
+ data: components["schemas"]["ActiveSummaryDto"];
20222
+ };
20223
+ };
20224
+ };
20225
+ /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header */
20226
+ 400: {
20227
+ headers: {
20228
+ [name: string]: unknown;
20229
+ };
20230
+ content: {
20231
+ /**
20232
+ * @example {
20233
+ * "error": {
20234
+ * "statusCode": 400,
20235
+ * "code": null,
20236
+ * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
20237
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20238
+ * "path": "/api/v1/oauth-clients/summary",
20239
+ * "method": "GET"
20240
+ * }
20241
+ * }
20242
+ */
20243
+ "application/json": components["schemas"]["ErrorResponseDto"];
20244
+ };
20245
+ };
20246
+ /** @description Invalid or expired token */
20247
+ 401: {
20248
+ headers: {
20249
+ [name: string]: unknown;
20250
+ };
20251
+ content: {
20252
+ /**
20253
+ * @example {
20254
+ * "error": {
20255
+ * "statusCode": 401,
20256
+ * "code": null,
20257
+ * "message": "Invalid or expired token",
20258
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20259
+ * "path": "/api/v1/oauth-clients",
20260
+ * "method": "GET"
20261
+ * }
20262
+ * }
20263
+ */
20264
+ "application/json": components["schemas"]["ErrorResponseDto"];
20265
+ };
20266
+ };
20267
+ /** @description The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment */
20268
+ 403: {
20269
+ headers: {
20270
+ [name: string]: unknown;
20271
+ };
20272
+ content: {
20273
+ /**
20274
+ * @example {
20275
+ * "error": {
20276
+ * "statusCode": 403,
20277
+ * "code": null,
20278
+ * "message": "The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment",
20279
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20280
+ * "path": "/api/v1/oauth-clients",
20281
+ * "method": "GET"
20282
+ * }
20283
+ * }
20284
+ */
20285
+ "application/json": components["schemas"]["ErrorResponseDto"];
20286
+ };
20287
+ };
20288
+ };
20289
+ };
20290
+ ApiOAuthClientsController_get: {
20291
+ parameters: {
20292
+ query?: never;
20293
+ header?: never;
20294
+ path: {
20295
+ id: string;
20296
+ };
20297
+ cookie?: never;
20298
+ };
20299
+ requestBody?: never;
20300
+ responses: {
20301
+ /** @description OAuth client returned */
20302
+ 200: {
20303
+ headers: {
20304
+ [name: string]: unknown;
20305
+ };
20306
+ content: {
20307
+ "application/json": {
20308
+ data: components["schemas"]["OAuthClientResponseDto"];
20309
+ };
20310
+ };
20311
+ };
20312
+ /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
20313
+ 400: {
20314
+ headers: {
20315
+ [name: string]: unknown;
20316
+ };
20317
+ content: {
20318
+ /**
20319
+ * @example {
20320
+ * "error": {
20321
+ * "statusCode": 400,
20322
+ * "code": null,
20323
+ * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
20324
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20325
+ * "path": "/api/v1/oauth-clients/{id}",
20326
+ * "method": "GET"
20327
+ * }
20328
+ * }
20329
+ */
20330
+ "application/json": components["schemas"]["ErrorResponseDto"];
20331
+ };
20332
+ };
20333
+ /** @description Invalid or expired token */
20334
+ 401: {
20335
+ headers: {
20336
+ [name: string]: unknown;
20337
+ };
20338
+ content: {
20339
+ /**
20340
+ * @example {
20341
+ * "error": {
20342
+ * "statusCode": 401,
20343
+ * "code": null,
20344
+ * "message": "Invalid or expired token",
20345
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20346
+ * "path": "/api/v1/oauth-clients",
20347
+ * "method": "GET"
20348
+ * }
20349
+ * }
20350
+ */
20351
+ "application/json": components["schemas"]["ErrorResponseDto"];
20352
+ };
20353
+ };
20354
+ /** @description The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment */
20355
+ 403: {
20356
+ headers: {
20357
+ [name: string]: unknown;
20358
+ };
20359
+ content: {
20360
+ /**
20361
+ * @example {
20362
+ * "error": {
20363
+ * "statusCode": 403,
20364
+ * "code": null,
20365
+ * "message": "The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment",
20366
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20367
+ * "path": "/api/v1/oauth-clients",
20368
+ * "method": "GET"
20369
+ * }
20370
+ * }
20371
+ */
20372
+ "application/json": components["schemas"]["ErrorResponseDto"];
20373
+ };
20374
+ };
20375
+ /** @description No OAuth client with that id exists in this Environment */
20376
+ 404: {
20377
+ headers: {
20378
+ [name: string]: unknown;
20379
+ };
20380
+ content: {
20381
+ /**
20382
+ * @example {
20383
+ * "error": {
20384
+ * "statusCode": 404,
20385
+ * "code": null,
20386
+ * "message": "No OAuth client with that id exists in this Environment",
20387
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20388
+ * "path": "/api/v1/oauth-clients/{id}",
20389
+ * "method": "GET"
20390
+ * }
20391
+ * }
20392
+ */
20393
+ "application/json": components["schemas"]["ErrorResponseDto"];
20394
+ };
20395
+ };
20396
+ };
20397
+ };
20398
+ ApiOAuthClientsController_remove: {
20399
+ parameters: {
20400
+ query?: never;
20401
+ header?: never;
20402
+ path: {
20403
+ id: string;
20404
+ };
20405
+ cookie?: never;
20406
+ };
20407
+ requestBody?: never;
20408
+ responses: {
20409
+ /** @description OAuth client deleted */
20410
+ 204: {
20411
+ headers: {
20412
+ [name: string]: unknown;
20413
+ };
20414
+ content?: never;
20415
+ };
20416
+ /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
20417
+ 400: {
20418
+ headers: {
20419
+ [name: string]: unknown;
20420
+ };
20421
+ content: {
20422
+ /**
20423
+ * @example {
20424
+ * "error": {
20425
+ * "statusCode": 400,
20426
+ * "code": null,
20427
+ * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
20428
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20429
+ * "path": "/api/v1/oauth-clients/{id}",
20430
+ * "method": "GET"
20431
+ * }
20432
+ * }
20433
+ */
20434
+ "application/json": components["schemas"]["ErrorResponseDto"];
20435
+ };
20436
+ };
20437
+ /** @description Invalid or expired token */
20438
+ 401: {
20439
+ headers: {
20440
+ [name: string]: unknown;
20441
+ };
20442
+ content: {
20443
+ /**
20444
+ * @example {
20445
+ * "error": {
20446
+ * "statusCode": 401,
20447
+ * "code": null,
20448
+ * "message": "Invalid or expired token",
20449
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20450
+ * "path": "/api/v1/oauth-clients",
20451
+ * "method": "GET"
20452
+ * }
20453
+ * }
20454
+ */
20455
+ "application/json": components["schemas"]["ErrorResponseDto"];
20456
+ };
20457
+ };
20458
+ /** @description The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment */
20459
+ 403: {
20460
+ headers: {
20461
+ [name: string]: unknown;
20462
+ };
20463
+ content: {
20464
+ /**
20465
+ * @example {
20466
+ * "error": {
20467
+ * "statusCode": 403,
20468
+ * "code": null,
20469
+ * "message": "The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment",
20470
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20471
+ * "path": "/api/v1/oauth-clients",
20472
+ * "method": "GET"
20473
+ * }
20474
+ * }
20475
+ */
20476
+ "application/json": components["schemas"]["ErrorResponseDto"];
20477
+ };
20478
+ };
20479
+ /** @description No OAuth client with that id exists in this Environment */
20480
+ 404: {
20481
+ headers: {
20482
+ [name: string]: unknown;
20483
+ };
20484
+ content: {
20485
+ /**
20486
+ * @example {
20487
+ * "error": {
20488
+ * "statusCode": 404,
20489
+ * "code": null,
20490
+ * "message": "No OAuth client with that id exists in this Environment",
20491
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20492
+ * "path": "/api/v1/oauth-clients/{id}",
20493
+ * "method": "DELETE"
20494
+ * }
20495
+ * }
20496
+ */
20497
+ "application/json": components["schemas"]["ErrorResponseDto"];
20498
+ };
20499
+ };
20500
+ };
20501
+ };
20502
+ ApiOAuthClientsController_update: {
20503
+ parameters: {
20504
+ query?: never;
20505
+ header?: never;
20506
+ path: {
20507
+ id: string;
20508
+ };
20509
+ cookie?: never;
20510
+ };
20511
+ requestBody: {
20512
+ content: {
20513
+ "application/json": components["schemas"]["UpdateOAuthClientDto"];
20514
+ };
20515
+ };
20516
+ responses: {
20517
+ /** @description OAuth client updated */
20518
+ 200: {
20519
+ headers: {
20520
+ [name: string]: unknown;
20521
+ };
20522
+ content: {
20523
+ "application/json": {
20524
+ data: components["schemas"]["OAuthClientResponseDto"];
20525
+ };
20526
+ };
20527
+ };
20528
+ /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range, `backchannel_logout_uri` names an address Canopy's servers will not call, or `initiate_login_uri` is malformed or not `https` (loopback hosts excepted); or the request sent both an `X-API-Key` and an `Authorization` header */
20529
+ 400: {
20530
+ headers: {
20531
+ [name: string]: unknown;
20532
+ };
20533
+ content: {
20534
+ /**
20535
+ * @example {
20536
+ * "error": {
20537
+ * "statusCode": 400,
20538
+ * "code": null,
20539
+ * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range, `backchannel_logout_uri` names an address Canopy's servers will not call, or `initiate_login_uri` is malformed or not `https` (loopback hosts excepted); or the request sent both an `X-API-Key` and an `Authorization` header",
20540
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20541
+ * "path": "/api/v1/oauth-clients/{id}",
20542
+ * "method": "PATCH"
20543
+ * }
20544
+ * }
20545
+ */
20546
+ "application/json": components["schemas"]["ErrorResponseDto"];
20547
+ };
20548
+ };
20549
+ /** @description Invalid or expired token */
20550
+ 401: {
20551
+ headers: {
20552
+ [name: string]: unknown;
20553
+ };
20554
+ content: {
20555
+ /**
20556
+ * @example {
20557
+ * "error": {
20558
+ * "statusCode": 401,
20559
+ * "code": null,
20560
+ * "message": "Invalid or expired token",
20561
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20562
+ * "path": "/api/v1/oauth-clients",
20563
+ * "method": "GET"
20564
+ * }
20565
+ * }
20566
+ */
20567
+ "application/json": components["schemas"]["ErrorResponseDto"];
20568
+ };
20569
+ };
20570
+ /** @description The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment */
20571
+ 403: {
20572
+ headers: {
20573
+ [name: string]: unknown;
20574
+ };
20575
+ content: {
20576
+ /**
20577
+ * @example {
20578
+ * "error": {
20579
+ * "statusCode": 403,
20580
+ * "code": null,
20581
+ * "message": "The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment",
20582
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20583
+ * "path": "/api/v1/oauth-clients",
20584
+ * "method": "GET"
20585
+ * }
20586
+ * }
20587
+ */
20588
+ "application/json": components["schemas"]["ErrorResponseDto"];
20589
+ };
20590
+ };
20591
+ /** @description No OAuth client with that id exists in this Environment */
20592
+ 404: {
20593
+ headers: {
20594
+ [name: string]: unknown;
20595
+ };
20596
+ content: {
20597
+ /**
20598
+ * @example {
20599
+ * "error": {
20600
+ * "statusCode": 404,
20601
+ * "code": null,
20602
+ * "message": "No OAuth client with that id exists in this Environment",
20603
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20604
+ * "path": "/api/v1/oauth-clients/{id}",
20605
+ * "method": "PATCH"
20606
+ * }
20607
+ * }
20608
+ */
20609
+ "application/json": components["schemas"]["ErrorResponseDto"];
20610
+ };
20611
+ };
20612
+ };
20613
+ };
20614
+ ApiOAuthClientsController_rotateSecret: {
20615
+ parameters: {
20616
+ query?: never;
20617
+ header?: never;
20618
+ path: {
20619
+ id: string;
20620
+ };
20621
+ cookie?: never;
20622
+ };
20623
+ requestBody?: never;
20624
+ responses: {
20625
+ /** @description OAuth client secret rotated — the new secret is only shown once */
20626
+ 200: {
20627
+ headers: {
20628
+ [name: string]: unknown;
20629
+ };
20630
+ content: {
20631
+ "application/json": {
20632
+ data: components["schemas"]["OAuthClientSecretRotatedResponseDto"];
20633
+ };
20634
+ };
20635
+ };
20636
+ /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
20637
+ 400: {
20638
+ headers: {
20639
+ [name: string]: unknown;
20640
+ };
20641
+ content: {
20642
+ /**
20643
+ * @example {
20644
+ * "error": {
20645
+ * "statusCode": 400,
20646
+ * "code": null,
20647
+ * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
20648
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20649
+ * "path": "/api/v1/oauth-clients/{id}",
20650
+ * "method": "GET"
20651
+ * }
20652
+ * }
20653
+ */
20654
+ "application/json": components["schemas"]["ErrorResponseDto"];
20655
+ };
20656
+ };
20657
+ /** @description Invalid or expired token */
20658
+ 401: {
20659
+ headers: {
20660
+ [name: string]: unknown;
20661
+ };
20662
+ content: {
20663
+ /**
20664
+ * @example {
20665
+ * "error": {
20666
+ * "statusCode": 401,
20667
+ * "code": null,
20668
+ * "message": "Invalid or expired token",
20669
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20670
+ * "path": "/api/v1/oauth-clients",
20671
+ * "method": "GET"
20672
+ * }
20673
+ * }
20674
+ */
20675
+ "application/json": components["schemas"]["ErrorResponseDto"];
20676
+ };
20677
+ };
20678
+ /** @description The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment */
20679
+ 403: {
20680
+ headers: {
20681
+ [name: string]: unknown;
20682
+ };
20683
+ content: {
20684
+ /**
20685
+ * @example {
20686
+ * "error": {
20687
+ * "statusCode": 403,
20688
+ * "code": null,
20689
+ * "message": "The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment",
20690
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20691
+ * "path": "/api/v1/oauth-clients",
20692
+ * "method": "GET"
20693
+ * }
20694
+ * }
20695
+ */
20696
+ "application/json": components["schemas"]["ErrorResponseDto"];
20697
+ };
20698
+ };
20699
+ /** @description No OAuth client with that id exists in this Environment */
20700
+ 404: {
20701
+ headers: {
20702
+ [name: string]: unknown;
20703
+ };
20704
+ content: {
20705
+ /**
20706
+ * @example {
20707
+ * "error": {
20708
+ * "statusCode": 404,
20709
+ * "code": null,
20710
+ * "message": "No OAuth client with that id exists in this Environment",
20711
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20712
+ * "path": "/api/v1/oauth-clients/{id}/rotate-secret",
20713
+ * "method": "POST"
20714
+ * }
20715
+ * }
20716
+ */
20717
+ "application/json": components["schemas"]["ErrorResponseDto"];
20718
+ };
20719
+ };
20720
+ };
20721
+ };
20722
+ ApiApiKeysController_list: {
20723
+ parameters: {
20724
+ query?: {
20725
+ /** @description Page number (1-based) */
20726
+ page?: number;
20727
+ /** @description Items per page (1-100, default 20) */
20728
+ take?: number;
20729
+ /** @description Search term */
20730
+ q?: string;
20731
+ /** @description Column to sort by. Allowed values depend on the endpoint. */
20732
+ sort_by?: string;
20733
+ /** @description Sort direction */
20734
+ order?: "asc" | "desc";
20735
+ };
20736
+ header?: never;
20737
+ path?: never;
20738
+ cookie?: never;
20739
+ };
20740
+ requestBody?: never;
20741
+ responses: {
20742
+ /** @description Paginated list */
20743
+ 200: {
20744
+ headers: {
20745
+ [name: string]: unknown;
20746
+ };
20747
+ content: {
20748
+ "application/json": {
20749
+ items: components["schemas"]["ApiKeyResponseDto"][];
20750
+ pagination: components["schemas"]["PageMetaDto"];
20751
+ };
20752
+ };
20753
+ };
20754
+ /** @description The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header */
20755
+ 400: {
20756
+ headers: {
20757
+ [name: string]: unknown;
20758
+ };
20759
+ content: {
20760
+ /**
20761
+ * @example {
20762
+ * "error": {
20763
+ * "statusCode": 400,
20764
+ * "code": null,
20765
+ * "message": "The request failed validation: a body field, a query parameter or an id in the path is missing, malformed or out of range; or the request sent both an `X-API-Key` and an `Authorization` header",
20766
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20767
+ * "path": "/api/v1/api-keys",
20768
+ * "method": "GET"
20769
+ * }
20770
+ * }
20771
+ */
20772
+ "application/json": components["schemas"]["ErrorResponseDto"];
20773
+ };
20774
+ };
20775
+ /** @description Invalid or expired token */
20776
+ 401: {
20777
+ headers: {
20778
+ [name: string]: unknown;
20779
+ };
20780
+ content: {
20781
+ /**
20782
+ * @example {
20783
+ * "error": {
20784
+ * "statusCode": 401,
20785
+ * "code": null,
20786
+ * "message": "Invalid or expired token",
20787
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20788
+ * "path": "/api/v1/api-keys",
20789
+ * "method": "GET"
20790
+ * }
20791
+ * }
20792
+ */
20793
+ "application/json": components["schemas"]["ErrorResponseDto"];
20794
+ };
20795
+ };
20796
+ /** @description The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment */
20797
+ 403: {
20798
+ headers: {
20799
+ [name: string]: unknown;
20800
+ };
20801
+ content: {
20802
+ /**
20803
+ * @example {
20804
+ * "error": {
20805
+ * "statusCode": 403,
20806
+ * "code": null,
20807
+ * "message": "The bearer token is not an admin or platform token, or the caller lacks the permission this operation checks: a scoped API key without that scope, an admin without the Account capability that covers it, or, for a node-scoped check, a node outside this Environment",
20808
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20809
+ * "path": "/api/v1/api-keys",
20810
+ * "method": "GET"
20811
+ * }
20812
+ * }
20813
+ */
20814
+ "application/json": components["schemas"]["ErrorResponseDto"];
20815
+ };
20816
+ };
20817
+ };
20818
+ };
20819
+ ApiApiKeysController_create: {
20820
+ parameters: {
20821
+ query?: never;
20822
+ header?: never;
20823
+ path?: never;
20824
+ cookie?: never;
20825
+ };
20826
+ requestBody: {
20827
+ content: {
20828
+ "application/json": components["schemas"]["CreateApiKeyDto"];
20829
+ };
20830
+ };
20831
+ responses: {
20832
+ /** @description API key created — key value is only shown once */
20833
+ 201: {
20834
+ headers: {
20835
+ [name: string]: unknown;
20836
+ };
20837
+ content: {
20838
+ "application/json": {
20839
+ data: components["schemas"]["ApiKeyCreatedResponseDto"];
20131
20840
  };
20132
20841
  };
20133
20842
  };
@@ -20215,6 +20924,27 @@ interface operations {
20215
20924
  "application/json": components["schemas"]["ErrorResponseDto"];
20216
20925
  };
20217
20926
  };
20927
+ /** @description The `Idempotency-Key` was already used by this caller for a request with a different method, path or body. A replay must repeat the original request exactly; a new request takes a new key. */
20928
+ 422: {
20929
+ headers: {
20930
+ [name: string]: unknown;
20931
+ };
20932
+ content: {
20933
+ /**
20934
+ * @example {
20935
+ * "error": {
20936
+ * "statusCode": 422,
20937
+ * "code": null,
20938
+ * "message": "The `Idempotency-Key` was already used by this caller for a request with a different method, path or body. A replay must repeat the original request exactly; a new request takes a new key.",
20939
+ * "timestamp": "2026-04-20T12:00:00.000Z",
20940
+ * "path": "/api/v1/api-keys",
20941
+ * "method": "POST"
20942
+ * }
20943
+ * }
20944
+ */
20945
+ "application/json": components["schemas"]["ErrorResponseDto"];
20946
+ };
20947
+ };
20218
20948
  /** @description More than 20 create requests in a minute from this caller (`x-canopy-rate-limit`); retry after the window */
20219
20949
  429: {
20220
20950
  headers: {
@@ -20694,14 +21424,14 @@ declare class Identities {
20694
21424
  get(id: string): Promise<ResponseBody<"ApiIdentitiesController_getIdentity">>;
20695
21425
  create(input: RequestBody<"ApiIdentitiesController_createIdentity">): Promise<ResponseBody<"ApiIdentitiesController_createIdentity">>;
20696
21426
  update(id: string, input: RequestBody<"ApiIdentitiesController_updateIdentity">): Promise<ResponseBody<"ApiIdentitiesController_updateIdentity">>;
20697
- delete(id: string): Promise<void>;
20698
21427
  /**
20699
- * Deactivation is the reversible counterpart to `delete` — sessions are
20700
- * revoked and sign-in refused, but the identity and its assignments survive.
20701
- * Prefer it for offboarding you may need to undo.
21428
+ * Takes the identity out of this key's Environment: its membership here is
21429
+ * deactivated and its role assignments here are dropped. The identity and
21430
+ * its access to other Environments are untouched. Deactivating an identity
21431
+ * everywhere is an Account-level action, not available to an
21432
+ * Environment-scoped key.
20702
21433
  */
20703
- deactivate(id: string): Promise<ResponseBody<"ApiIdentitiesController_deactivateIdentity">>;
20704
- activate(id: string): Promise<ResponseBody<"ApiIdentitiesController_activateIdentity">>;
21434
+ delete(id: string): Promise<void>;
20705
21435
  /**
20706
21436
  * Every role this identity holds, and where — across all pages.
20707
21437
  *
@@ -20739,7 +21469,7 @@ declare class Identities {
20739
21469
  * Ends every session the identity holds, so the next refresh on any device
20740
21470
  * fails and the person signs in again. Access tokens already issued keep
20741
21471
  * working until their short lifetime runs out. For a suspected compromise;
20742
- * `deactivate` also refuses the next sign-in.
21472
+ * `delete` also takes the identity out of this Environment.
20743
21473
  */
20744
21474
  revokeSessions(id: string): Promise<void>;
20745
21475
  }
@@ -20991,6 +21721,12 @@ declare class Canopy {
20991
21721
  constructor(options: CanopyClientOptions);
20992
21722
  }
20993
21723
 
21724
+ /**
21725
+ * The longest a held answer may be kept: five minutes. `ttlMs` is the delay
21726
+ * between an access change and it taking effect, and Canopy promises that
21727
+ * delay is short, so a longer value is refused rather than honoured.
21728
+ */
21729
+ declare const MAX_TTL_MS = 300000;
20994
21730
  interface LocalAuthorizerOptions {
20995
21731
  /**
20996
21732
  * How long grant roots and the hierarchy are reused, in milliseconds.
@@ -21007,6 +21743,10 @@ interface LocalAuthorizerOptions {
21007
21743
  * for a caller who cannot accept a stale allow at all — it costs a round trip
21008
21744
  * per request, which is what this class exists to avoid, so reach for it
21009
21745
  * knowingly rather than as a default.
21746
+ *
21747
+ * **At most {@link MAX_TTL_MS} (five minutes).** A longer value, a negative
21748
+ * one or a non-number throws when the authorizer is created, rather than
21749
+ * quietly stretching how long a revoked user keeps access.
21010
21750
  */
21011
21751
  ttlMs?: number;
21012
21752
  /**
@@ -21082,7 +21822,9 @@ declare class LocalAuthorizer {
21082
21822
  * With no argument, everything goes: grants and the hierarchy tree. Not
21083
21823
  * needed in normal operation, where entries expire on their own; useful in
21084
21824
  * tests and after a change whose reach you cannot name (a role's
21085
- * permissions edited, a node moved).
21825
+ * permissions edited, a role deactivated or reactivated, a node moved). A
21826
+ * deactivated role grants nothing to anyone holding it, so until the cache
21827
+ * is cleared or expires, its holders keep being allowed locally.
21086
21828
  *
21087
21829
  * Multi-instance honesty: an invalidation reaches THIS process only. A
21088
21830
  * webhook lands on one instance behind a load balancer; the others serve
@@ -21251,11 +21993,22 @@ declare function isCanopyTokenError(error: unknown): error is CanopyTokenError;
21251
21993
 
21252
21994
  interface TokenVerifierOptions {
21253
21995
  /**
21254
- * The issuer whose tokens are accepted, matched against `iss` exactly.
21255
- * Defaults to Canopy's hosted issuer; set it for a self-hosted instance.
21996
+ * The Environment whose tokens are accepted. Every Environment is its own
21997
+ * issuer with its own signing keys, at
21998
+ * `https://auth.canopy-io.com/environments/<id>`, so on hosted Canopy this is
21999
+ * all verification needs. A token from any other Environment fails.
22000
+ *
22001
+ * Set exactly one of `environmentId` and `issuer`; the constructor throws
22002
+ * with neither or both.
22003
+ */
22004
+ environmentId?: string;
22005
+ /**
22006
+ * The issuer whose tokens are accepted, matched against `iss` exactly. Set it
22007
+ * instead of `environmentId` on a custom auth domain (`https://auth.acme.com`)
22008
+ * or a self-hosted instance (`<origin>/environments/<id>`).
21256
22009
  *
21257
- * Safe to default because it fails closed: pointed at the wrong issuer, a
21258
- * token is rejected rather than accepted.
22010
+ * Pointed at the wrong issuer, verification fails closed: a token is
22011
+ * rejected, never mistakenly accepted.
21259
22012
  */
21260
22013
  issuer?: string;
21261
22014
  /**
@@ -21479,4 +22232,4 @@ type WebhookEventData<Name extends WebhookEventName> = WebhookEvent<Name>["data"
21479
22232
  */
21480
22233
  declare function isWebhookEvent<Name extends WebhookEventName>(delivery: WebhookDelivery, name: Name): delivery is WebhookEvent<Name>;
21481
22234
 
21482
- export { type AssignmentItem, Assignments, type CallOptions, Canopy, CanopyAuthorizerError, CanopyClient, type CanopyClientOptions, CanopyConnectionError, CanopyError, type CanopyErrorBody, type CanopyOrgContext, type CanopyTokenClaims, CanopyTokenError, type Collection, type ConcurrencyOptions, type ConditionalResult, type CursorPagination, Identities, type IdentityAssignmentItem, type IdentityItem, type IdentitySessionItem, type LocalAuthorizationQuery, LocalAuthorizer, type LocalAuthorizerOptions, type LocalAuthorizerStats, type OffsetPagination, type OperationId, type OrganizationInviteItem, type OrganizationItem, type OrganizationMemberItem, Organizations, type PageFetcher, type PageParams, type PaginateOptions, type Pagination, Paginator, type PartialSuccess, type PermissionItem, Permissions, type QueryParams, type RequestBody, type RequestOptions, type ResponseBody, type RoleItem, Roles, type Schema, TokenVerifier, type TokenVerifierOptions, type WebhookDelivery, type WebhookEvent, type WebhookEventData, type WebhookEventName, type components, isCanopyAuthorizerError, isCanopyConnectionError, isCanopyError, isCanopyTokenError, isCursorPagination, isWebhookEvent, type operations, orgContext, paginate, type paths, withConcurrency };
22235
+ export { type AssignmentItem, Assignments, type CallOptions, Canopy, CanopyAuthorizerError, CanopyClient, type CanopyClientOptions, CanopyConnectionError, CanopyError, type CanopyErrorBody, type CanopyOrgContext, type CanopyTokenClaims, CanopyTokenError, type Collection, type ConcurrencyOptions, type ConditionalResult, type CursorPagination, Identities, type IdentityAssignmentItem, type IdentityItem, type IdentitySessionItem, type LocalAuthorizationQuery, LocalAuthorizer, type LocalAuthorizerOptions, type LocalAuthorizerStats, MAX_TTL_MS, type OffsetPagination, type OperationId, type OrganizationInviteItem, type OrganizationItem, type OrganizationMemberItem, Organizations, type PageFetcher, type PageParams, type PaginateOptions, type Pagination, Paginator, type PartialSuccess, type PermissionItem, Permissions, type QueryParams, type RequestBody, type RequestOptions, type ResponseBody, type RoleItem, Roles, type Schema, TokenVerifier, type TokenVerifierOptions, type WebhookDelivery, type WebhookEvent, type WebhookEventData, type WebhookEventName, type components, isCanopyAuthorizerError, isCanopyConnectionError, isCanopyError, isCanopyTokenError, isCursorPagination, isWebhookEvent, type operations, orgContext, paginate, type paths, withConcurrency };