@canopy-io/node 0.7.2 → 0.9.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.ts CHANGED
@@ -378,7 +378,7 @@ interface paths {
378
378
  put?: never;
379
379
  /**
380
380
  * Bulk evaluate authorization
381
- * @description Evaluates many permission checks in a single request, returning a `{ items }` array of decisions in the same order as the input `checks`, each with the same shape as the single evaluate endpoint. Every check is resolved independently against its own `identity_id`, `permission`, and `scope` (`node` lineage walk or `app_wide`). Scoped API keys must carry the evaluate scope (`403` otherwise). Rate-limited to 500 requests/minute.
381
+ * @description Evaluates up to 100 permission checks in a single request (more is refused with `400`), returning a `{ items }` array of decisions in the same order as the input `checks`, each with the same shape as the single evaluate endpoint. Every check is resolved independently against its own `identity_id`, `permission`, and `scope` (`node` lineage walk or `app_wide`). Scoped API keys must carry the evaluate scope (`403` otherwise). Rate-limited to 500 requests/minute.
382
382
  */
383
383
  post: operations["ApiPermissionsController_evaluateBulk"];
384
384
  delete?: never;
@@ -588,7 +588,7 @@ interface paths {
588
588
  };
589
589
  /**
590
590
  * List an identity's active sessions (admin)
591
- * @description Lists an identity's active sessions in the caller's Environment (server-to-server admin): the rows a customer reads to confirm from its own side that a sign-out took, or to show a person where they are signed in. Each row is a session's current refresh token, so `id` changes on every refresh. Sessions the identity holds in its other Environments are not listed. Returns `404` when the identity has no membership in this Environment.
591
+ * @description Lists one page of an identity's active sessions in the caller's Environment (server-to-server admin), newest first, taking `page` and `take` only: the rows a customer reads to confirm from its own side that a sign-out took, or to show a person where they are signed in. Each row is a session's current refresh token, so `id` changes on every refresh. Sessions the identity holds in its other Environments are not listed. Returns `404` when the identity has no membership in this Environment.
592
592
  */
593
593
  get: operations["ApiIdentitiesController_listIdentitySessions"];
594
594
  put?: never;
@@ -768,7 +768,7 @@ interface paths {
768
768
  };
769
769
  /**
770
770
  * Get where an identity holds each permission
771
- * @description Returns, for the current Environment, every permission the identity holds mapped to the hierarchy nodes its grants were made at — the nodes themselves, **not** expanded through their descendants. A grant already means "this node and everything beneath it", so a caller answers a node-scoped question by walking up from the node in question and looking for one of these roots, using a copy of the tree fetched once from `GET /api/v1/nodes` and shared across identities. Answers both scopes without a further call: the permission appearing at all is the Application-wide answer, and the walk is the node-scoped one. Scheduled assignments outside their effective window are excluded. Returns `404` when the identity has no membership in this Environment.
771
+ * @description Returns, for the current Environment, one page of `(permission, node_id)` rows: every permission the identity holds, paired with each hierarchy node its grants were made at — the nodes themselves, **not** expanded through their descendants. Rows are ordered by permission, then node; a caller building the whole map walks every page. A grant already means "this node and everything beneath it", so a caller answers a node-scoped question by walking up from the node in question and looking for one of these roots, using a copy of the parent edges fetched once from `GET /api/v1/nodes/parents` and shared across identities. Answers both scopes without a further call: the permission appearing at all is the Application-wide answer, and the walk is the node-scoped one. Scheduled assignments outside their effective window are excluded. Returns `404` when the identity has no membership in this Environment.
772
772
  */
773
773
  get: operations["ApiIdentitiesController_getIdentityGrants"];
774
774
  put?: never;
@@ -891,8 +891,8 @@ interface paths {
891
891
  cookie?: never;
892
892
  };
893
893
  /**
894
- * List hierarchy (scoped tree)
895
- * @description Returns the caller's accessible hierarchy as a nested tree for the current Environment, each node annotated with `access_state`, `can_access`, and `can_manage`. `user` principals (dashboard), which need the Console capability covering `hierarchy.view`, see the full tree; API-key principals see only the subtree their `access_mode`/scopes grant — `full_access` unlocks everything, while scoped keys see nodes reachable via `hierarchy.view`. The response also includes a `scope` block listing `accessible_node_ids`, `scope_root_node_ids`, and `entry_node_ids`.
894
+ * List hierarchy nodes (scoped, paged)
895
+ * @description Returns one page of the caller's hierarchy for the current Environment as a flat list, each node carrying its `parent_node_id` and annotated with `access_state`, `can_access`, `can_manage` and its identity counts. A caller rebuilding the tree walks every page and links each node to its parent; a node whose parent is not in the listing is a top of the caller's scope. `user` principals (dashboard), which need the Console capability covering `hierarchy.view`, see every node; API-key principals see only what their `access_mode`/scopes grant — `full_access` unlocks everything, while scoped keys see nodes reachable via `hierarchy.view`. `context_only` nodes are the ancestors shown as the path to the caller's scope. Searches names and slugs with `q`; sorts by `name` or `created` (default, oldest first).
896
896
  */
897
897
  get: operations["ApiNodesController_listNodes"];
898
898
  put?: never;
@@ -916,7 +916,7 @@ interface paths {
916
916
  };
917
917
  /**
918
918
  * List the hierarchy as parent edges
919
- * @description Returns the same hierarchy `GET /api/v1/nodes` describes, scoped identically, but as a flat list of `{ id, parent_node_id }` and nothing else. Intended for a client that evaluates authorization locally: it walks upward from a node and reads none of the tree's names, statuses, access flags or counts. At fifty thousand nodes the tree is roughly 18.6 MB against 4 MB of edges, on a read that runs at every consuming process's startup. Supports the same `If-None-Match` revalidation, with a validator distinct from the tree's — a tag from one representation never satisfies a request for the other.
919
+ * @description Returns the same hierarchy `GET /api/v1/nodes` describes, scoped identically, but as `{ id, parent_node_id }` pairs and nothing else, one page at a time, ordered by node id. Intended for a client that evaluates authorization locally: it walks every page into a child-to-parent map and reads none of the nodes' names, statuses, access flags or counts. At fifty thousand nodes the full listing is roughly 18.6 MB against 4 MB of edges, on a read that runs at every consuming process's startup. Supports the same `If-None-Match` revalidation, with a validator distinct from the node listing's and from every other page's: a tag from one representation or page never satisfies a request for another. A `304` on the first page means the whole hierarchy is unchanged.
920
920
  */
921
921
  get: operations["ApiNodesController_listNodeParents"];
922
922
  put?: never;
@@ -964,7 +964,7 @@ interface paths {
964
964
  };
965
965
  /**
966
966
  * Get subtree from a node
967
- * @description Returns the subtree rooted at the given node as a nested structure, drawn from the caller's accessible hierarchy in the current Environment. The node must be within the caller's accessible scope (otherwise `403`); a node id that resolves but is absent from the scoped tree returns `404`. Each node carries the same access annotations as the full tree listing.
967
+ * @description Returns one page of the given node and its descendants within the caller's scope in the current Environment, flat, each node carrying its `parent_node_id` and the same access annotations and counts as `GET /api/v1/nodes`. The node must be within the caller's accessible scope (otherwise `403`). Searches names and slugs with `q`; sorts by `name` or `created` (default, oldest first).
968
968
  */
969
969
  get: operations["ApiNodesController_getSubtree"];
970
970
  put?: never;
@@ -1004,7 +1004,7 @@ interface paths {
1004
1004
  };
1005
1005
  /**
1006
1006
  * Get direct children of a node
1007
- * @description Returns the direct children of a node as an `items` array (one level only, not the full subtree), scoped to the current Environment. The node must be within the caller's accessible scope, otherwise `403` is returned.
1007
+ * @description Returns one page of a node's direct children (one level only, not the full subtree) in the current Environment. The node must be within the caller's accessible scope, otherwise `403` is returned. Searches names and slugs with `q`; sorts by `name` or `created` (default, oldest first).
1008
1008
  */
1009
1009
  get: operations["ApiNodesController_getChildren"];
1010
1010
  put?: never;
@@ -1338,7 +1338,7 @@ interface paths {
1338
1338
  put?: never;
1339
1339
  /**
1340
1340
  * Add a member to an organization
1341
- * @description Adds a member: assigns `role_id` to `identity_id` at the organization. The identity must already hold an active membership in this Environment (invite by email instead for someone who does not). A member holds exactly one role per organization, so an identity that is already a member returns `409` — use the change-role operation. Requires the `rbac.manage_assignments` permission at the organization and emits `organization.member.added`.
1341
+ * @description Adds a member: assigns `role_id` to `identity_id` at the organization. The identity must already hold an active membership in this Environment (invite by email instead for someone who does not). A member holds exactly one role per organization, so an identity that is already a member returns `409` — use the change-role operation. Requires the `rbac.manage_assignments` permission at the organization and emits `organization.member.added`. An organization's own administrator, signed in with an identity token and admitted by `canopy:organization.manage` alone, is refused with `403` (`organization.member_add_requires_invite`): the person never agreed to join, so the administrator invites them instead.
1342
1342
  */
1343
1343
  post: operations["ApiOrganizationsController_addMember"];
1344
1344
  delete?: never;
@@ -1382,7 +1382,7 @@ interface paths {
1382
1382
  put?: never;
1383
1383
  /**
1384
1384
  * Reset a member's multi-factor authentication
1385
- * @description The organization's own administrator, or the developer, clears a member's multi-factor enrolment: every factor, the recovery codes and the trusted devices, so the person enrols afresh at their next sign-in. For a member who lost their authenticator. Sessions already open are left alone. Audited as `identity.mfa.admin.forced_reset`. Returns `404` when the identity is not a member. Responds `204 No Content`; requires `hierarchy.manage` or `canopy:organization.manage` at the organization.
1385
+ * @description The organization's own administrator, or the developer, clears a member's multi-factor enrolment: every factor and the recovery codes, held once per identity, and the devices trusted in this Environment, so the person enrols afresh at their next sign-in. For a member who lost their authenticator. Sessions already open are left alone. Audited as `identity.mfa.admin.forced_reset`. Returns `404` when the identity is not a member. Responds `204 No Content`; requires `hierarchy.manage` or `canopy:organization.manage` at the organization.
1386
1386
  */
1387
1387
  post: operations["ApiOrganizationsController_resetMemberMfa"];
1388
1388
  delete?: never;
@@ -1752,7 +1752,7 @@ interface paths {
1752
1752
  };
1753
1753
  /**
1754
1754
  * List the groups an organization's provider has pushed
1755
- * @description Pushed groups returned, each with its role mapping and member count
1755
+ * @description One page of pushed groups, each with its role mapping and member count, by display name unless sorted (`sort_by` `name` or `created`); `q` searches display names and external ids
1756
1756
  */
1757
1757
  get: operations["ApiOrganizationDirectoryGroupsController_list"];
1758
1758
  put?: never;
@@ -2270,7 +2270,7 @@ interface paths {
2270
2270
  put?: never;
2271
2271
  /**
2272
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`.
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`), each one of `openid`, `profile`, `email`, `org` and `permissions`; any other value is refused with `400` (`oauth.client_scope_unknown`). 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
2274
  */
2275
2275
  post: operations["ApiOAuthClientsController_create"];
2276
2276
  delete?: never;
@@ -2322,7 +2322,7 @@ interface paths {
2322
2322
  head?: never;
2323
2323
  /**
2324
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.
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. A `scopes` value outside `openid`, `profile`, `email`, `org` and `permissions` is refused with `400` (`oauth.client_scope_unknown`). Returns the updated client, or `404` when the client is not found in this Environment. The secret is not rotated here.
2326
2326
  */
2327
2327
  patch: operations["ApiOAuthClientsController_update"];
2328
2328
  trace?: never;
@@ -2383,14 +2383,14 @@ interface paths {
2383
2383
  post?: never;
2384
2384
  /**
2385
2385
  * Delete an API key
2386
- * @description Permanently deletes an API key from the active Environment. The row is removed entirely rather than just disabled, so the key can never authenticate again and disappears from listings; the lifecycle remains traceable in the audit log. Returns `204 No Content` on success and `404` when no key with the given id exists in the active Environment.
2386
+ * @description Permanently deletes an API key from the active Environment. The row is removed entirely rather than just disabled, so the key can never authenticate again and disappears from listings; the lifecycle remains traceable in the audit log. Returns `204 No Content` on success and `404` when no key with the given id exists in the active Environment. A scoped API key can act only on scoped keys whose scopes it holds itself; any other key is refused with `403`.
2387
2387
  */
2388
2388
  delete: operations["ApiApiKeysController_delete"];
2389
2389
  options?: never;
2390
2390
  head?: never;
2391
2391
  /**
2392
2392
  * Activate or deactivate an API key
2393
- * @description Enables or disables an existing API key in the current Environment via the `is_active` flag. Disabling is reversible: a disabled key is rejected by authentication immediately and can be re-enabled later. Returns the key's metadata with no secret. Returns `404` when no key with the given id exists in the active Environment.
2393
+ * @description Enables or disables an existing API key in the current Environment via the `is_active` flag. Disabling is reversible: a disabled key is rejected by authentication immediately and can be re-enabled later. Returns the key's metadata with no secret. Returns `404` when no key with the given id exists in the active Environment. A scoped API key can act only on scoped keys whose scopes it holds itself; any other key is refused with `403`.
2394
2394
  */
2395
2395
  patch: operations["ApiApiKeysController_update"];
2396
2396
  trace?: never;
@@ -2406,7 +2406,7 @@ interface paths {
2406
2406
  put?: never;
2407
2407
  /**
2408
2408
  * Rotate an API key's secret
2409
- * @description Rotates the secret of an existing API key in place, minting a brand-new `cnpy_`-prefixed value for the same row while preserving its id, name, `scopes`, `access_mode`, expiry, and audit lineage. The previous secret is invalidated immediately and the new plaintext is returned exactly once in the `key` field. `is_active` is left untouched — rotating does not re-enable a disabled key. Returns `404` when no key with the given id exists in the active Environment.
2409
+ * @description Rotates the secret of an existing API key in place, minting a brand-new `cnpy_`-prefixed value for the same row while preserving its id, name, `scopes`, `access_mode`, expiry, and audit lineage. The previous secret is invalidated immediately and the new plaintext is returned exactly once in the `key` field. `is_active` is left untouched — rotating does not re-enable a disabled key. Returns `404` when no key with the given id exists in the active Environment. A scoped API key can act only on scoped keys whose scopes it holds itself; any other key is refused with `403`.
2410
2410
  */
2411
2411
  post: operations["ApiApiKeysController_rotateSecret"];
2412
2412
  delete?: never;
@@ -2476,11 +2476,11 @@ interface components {
2476
2476
  allowed: boolean;
2477
2477
  permission: string;
2478
2478
  /**
2479
- * @description Echo of the `scope` the caller asked for. `app_wide` answers are 'matched somewhere in the tree' — never treat them as scoped to a specific node.
2479
+ * @description Echo of the `scope` the caller asked for. `app_wide` answers are 'matched somewhere in the Environment' — never treat them as scoped to a specific node.
2480
2480
  * @enum {string}
2481
2481
  */
2482
2482
  scope_evaluated: "node" | "app_wide";
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. */
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 covers the whole Environment, not one node. */
2484
2484
  effective_node_id?: string | null;
2485
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. */
2486
2486
  granting_roles: string[];
@@ -2491,7 +2491,7 @@ interface components {
2491
2491
  identity_id: string;
2492
2492
  permission: string;
2493
2493
  /**
2494
- * @description Required. `node` asks 'does this identity have the permission *at* `node_id`?' (lineage walk). `app_wide` asks the coarse-grained 'does this identity have the permission *anywhere* in the org?' question — useful for UI gating, **never** for resource-scoped enforcement. `node` requires `node_id`; `app_wide` forbids it.
2494
+ * @description Required. `node` asks 'does this identity have the permission *at* `node_id`?' (lineage walk). `app_wide` asks the coarse-grained 'does this identity have the permission *anywhere* in the Environment?' question — useful for UI gating, **never** for resource-scoped enforcement. `node` requires `node_id`; `app_wide` forbids it.
2495
2495
  * @enum {string}
2496
2496
  */
2497
2497
  scope: "node" | "app_wide";
@@ -2503,7 +2503,7 @@ interface components {
2503
2503
  identity_id: string;
2504
2504
  permission: string;
2505
2505
  /**
2506
- * @description Required. `node` asks 'does this identity have the permission *at* `node_id`?' (lineage walk). `app_wide` asks the coarse-grained 'does this identity have the permission *anywhere* in the org?' question — useful for UI gating, **never** for resource-scoped enforcement. `node` requires `node_id`; `app_wide` forbids it.
2506
+ * @description Required. `node` asks 'does this identity have the permission *at* `node_id`?' (lineage walk). `app_wide` asks the coarse-grained 'does this identity have the permission *anywhere* in the Environment?' question — useful for UI gating, **never** for resource-scoped enforcement. `node` requires `node_id`; `app_wide` forbids it.
2507
2507
  * @enum {string}
2508
2508
  */
2509
2509
  scope: "node" | "app_wide";
@@ -2511,6 +2511,7 @@ interface components {
2511
2511
  node_id?: string;
2512
2512
  };
2513
2513
  BulkEvaluatePermissionDto: {
2514
+ /** @description Between 1 and 100 checks. More is refused with a 400. */
2514
2515
  checks: components["schemas"]["EvaluateCheckDto"][];
2515
2516
  };
2516
2517
  PermissionTraceAssignmentDto: {
@@ -2741,8 +2742,11 @@ interface components {
2741
2742
  IdentityGrantResponseDto: {
2742
2743
  /** @example reports.view */
2743
2744
  permission: string;
2744
- /** @description Hierarchy node ids the permission was granted at. Not expanded through descendants. */
2745
- nodes: string[];
2745
+ /**
2746
+ * Format: uuid
2747
+ * @description The hierarchy node the permission was granted at. Not expanded through descendants.
2748
+ */
2749
+ node_id: string;
2746
2750
  };
2747
2751
  IdentityInviteResponseDto: {
2748
2752
  id: string;
@@ -2862,7 +2866,7 @@ interface components {
2862
2866
  /** @description Arbitrary metadata */
2863
2867
  metadata?: Record<string, unknown>;
2864
2868
  };
2865
- HierarchyTreeNodeDto: {
2869
+ ScopedNodeResponseDto: {
2866
2870
  id: string;
2867
2871
  name: string;
2868
2872
  /** @description Optional free-text description shown under the node name. */
@@ -2876,7 +2880,6 @@ interface components {
2876
2880
  access_state: "accessible" | "context_only";
2877
2881
  can_access: boolean;
2878
2882
  can_manage: boolean;
2879
- children: components["schemas"]["HierarchyTreeNodeDto"][];
2880
2883
  /** @description Optimistic-lock version. Send back as the `If-Match` header when mutating this node to detect concurrent edits. */
2881
2884
  version: number;
2882
2885
  /** @description Distinct active identities directly assigned at this node (excludes inherited). */
@@ -2884,15 +2887,6 @@ interface components {
2884
2887
  /** @description Distinct active identities inherited from this node's ancestors. */
2885
2888
  inherited_count: number;
2886
2889
  };
2887
- HierarchyScopeDto: {
2888
- accessible_node_ids: string[];
2889
- scope_root_node_ids: string[];
2890
- entry_node_ids: string[];
2891
- };
2892
- ScopedHierarchyTreeResponseDto: {
2893
- tree: components["schemas"]["HierarchyTreeNodeDto"][];
2894
- scope: components["schemas"]["HierarchyScopeDto"];
2895
- };
2896
2890
  NodeParentEdgeResponseDto: {
2897
2891
  id: string;
2898
2892
  /** @description Null for the root node, which has no parent. */
@@ -6276,12 +6270,14 @@ interface operations {
6276
6270
  page?: number;
6277
6271
  /** @description Items per page (1-100, default 20) */
6278
6272
  take?: number;
6279
- /** @description Search term */
6273
+ /** @description Search names and emails */
6280
6274
  q?: string;
6281
- /** @description Column to sort by. Allowed values depend on the endpoint. */
6282
- sort_by?: string;
6275
+ /** @description Sort column. Defaults to `name`, A to Z. */
6276
+ sort_by?: "name" | "email" | "created";
6283
6277
  /** @description Sort direction */
6284
6278
  order?: "asc" | "desc";
6279
+ /** @description Filter by active/inactive status. Omit to show all. */
6280
+ status?: "active" | "inactive";
6285
6281
  };
6286
6282
  header?: never;
6287
6283
  path?: never;
@@ -6504,16 +6500,16 @@ interface operations {
6504
6500
  page?: number;
6505
6501
  /** @description Items per page (1-100, default 20) */
6506
6502
  take?: number;
6507
- /** @description Search term */
6503
+ /** @description Search names and emails */
6508
6504
  q?: string;
6509
- /** @description Column to sort by. Allowed values depend on the endpoint. */
6510
- sort_by?: string;
6505
+ /** @description Sort column. Defaults to `name`, A to Z. */
6506
+ sort_by?: "name" | "email" | "created";
6511
6507
  /** @description Sort direction */
6512
6508
  order?: "asc" | "desc";
6513
- /** @description Filter by role ID (UUID) or "no_assignment" for unassigned identities */
6514
- role_id?: string;
6515
6509
  /** @description Filter by active/inactive status. Omit to show all. */
6516
6510
  status?: "active" | "inactive";
6511
+ /** @description Filter by role ID (UUID) or "no_assignment" for unassigned identities */
6512
+ role_id?: string;
6517
6513
  };
6518
6514
  header?: never;
6519
6515
  path?: never;
@@ -7495,7 +7491,12 @@ interface operations {
7495
7491
  };
7496
7492
  ApiIdentitiesController_listIdentitySessions: {
7497
7493
  parameters: {
7498
- query?: never;
7494
+ query?: {
7495
+ /** @description Page number (1-based) */
7496
+ page?: number;
7497
+ /** @description Items per page (1-100, default 20) */
7498
+ take?: number;
7499
+ };
7499
7500
  header?: never;
7500
7501
  path: {
7501
7502
  id: string;
@@ -7504,7 +7505,7 @@ interface operations {
7504
7505
  };
7505
7506
  requestBody?: never;
7506
7507
  responses: {
7507
- /** @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. */
7508
+ /** @description One page of the sessions the identity holds that are 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. */
7508
7509
  200: {
7509
7510
  headers: {
7510
7511
  [name: string]: unknown;
@@ -7512,6 +7513,7 @@ interface operations {
7512
7513
  content: {
7513
7514
  "application/json": {
7514
7515
  items: components["schemas"]["IdentitySessionResponseDto"][];
7516
+ pagination: components["schemas"]["PageMetaDto"];
7515
7517
  };
7516
7518
  };
7517
7519
  };
@@ -8241,10 +8243,10 @@ interface operations {
8241
8243
  page?: number;
8242
8244
  /** @description Items per page (1-100, default 20) */
8243
8245
  take?: number;
8244
- /** @description Search term */
8246
+ /** @description Search role and node names */
8245
8247
  q?: string;
8246
- /** @description Column to sort by. Allowed values depend on the endpoint. */
8247
- sort_by?: string;
8248
+ /** @description Sort column. Defaults to `created`, oldest first. */
8249
+ sort_by?: "role" | "node" | "created";
8248
8250
  /** @description Sort direction */
8249
8251
  order?: "asc" | "desc";
8250
8252
  };
@@ -8464,7 +8466,12 @@ interface operations {
8464
8466
  };
8465
8467
  ApiIdentitiesController_getIdentityGrants: {
8466
8468
  parameters: {
8467
- query?: never;
8469
+ query?: {
8470
+ /** @description Page number (1-based) */
8471
+ page?: number;
8472
+ /** @description Items per page (1-100, default 20) */
8473
+ take?: number;
8474
+ };
8468
8475
  header?: never;
8469
8476
  path: {
8470
8477
  id: string;
@@ -8473,7 +8480,7 @@ interface operations {
8473
8480
  };
8474
8481
  requestBody?: never;
8475
8482
  responses: {
8476
- /** @description Grant map returned */
8483
+ /** @description One page of grant roots, one row per permission and node, ordered by permission then node */
8477
8484
  200: {
8478
8485
  headers: {
8479
8486
  [name: string]: unknown;
@@ -8481,6 +8488,7 @@ interface operations {
8481
8488
  content: {
8482
8489
  "application/json": {
8483
8490
  items: components["schemas"]["IdentityGrantResponseDto"][];
8491
+ pagination: components["schemas"]["PageMetaDto"];
8484
8492
  };
8485
8493
  };
8486
8494
  };
@@ -9244,9 +9252,20 @@ interface operations {
9244
9252
  };
9245
9253
  ApiNodesController_listNodes: {
9246
9254
  parameters: {
9247
- query?: never;
9255
+ query?: {
9256
+ /** @description Page number (1-based) */
9257
+ page?: number;
9258
+ /** @description Items per page (1-100, default 20) */
9259
+ take?: number;
9260
+ /** @description Search node names and slugs */
9261
+ q?: string;
9262
+ /** @description Sort column. Defaults to `created`, oldest first. */
9263
+ sort_by?: "name" | "created";
9264
+ /** @description Sort direction */
9265
+ order?: "asc" | "desc";
9266
+ };
9248
9267
  header?: {
9249
- /** @description An `ETag` from a previous response. Answers `304 Not Modified` when the hierarchy has not changed since, so a client holding a cached tree can revalidate on a short interval without re-reading it. */
9268
+ /** @description An `ETag` from a previous response for the same page and query. Answers `304 Not Modified` when the hierarchy has not changed since, so a client holding a cached copy can revalidate on a short interval without re-reading it. */
9250
9269
  "If-None-Match"?: string;
9251
9270
  };
9252
9271
  path?: never;
@@ -9254,25 +9273,26 @@ interface operations {
9254
9273
  };
9255
9274
  requestBody?: never;
9256
9275
  responses: {
9257
- /** @description Scoped hierarchy tree returned */
9276
+ /** @description One page of the caller's scoped nodes */
9258
9277
  200: {
9259
9278
  headers: {
9260
9279
  [name: string]: unknown;
9261
9280
  };
9262
9281
  content: {
9263
9282
  "application/json": {
9264
- data: components["schemas"]["ScopedHierarchyTreeResponseDto"];
9283
+ items: components["schemas"]["ScopedNodeResponseDto"][];
9284
+ pagination: components["schemas"]["PageMetaDto"];
9265
9285
  };
9266
9286
  };
9267
9287
  };
9268
- /** @description The hierarchy is unchanged since the supplied `ETag`. No body; keep using the cached tree. */
9288
+ /** @description The hierarchy is unchanged since the supplied `ETag`. No body; keep using the cached copy. */
9269
9289
  304: {
9270
9290
  headers: {
9271
9291
  [name: string]: unknown;
9272
9292
  };
9273
9293
  content?: never;
9274
9294
  };
9275
- /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
9295
+ /** @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 */
9276
9296
  400: {
9277
9297
  headers: {
9278
9298
  [name: string]: unknown;
@@ -9283,7 +9303,7 @@ interface operations {
9283
9303
  * "error": {
9284
9304
  * "statusCode": 400,
9285
9305
  * "code": null,
9286
- * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
9306
+ * "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",
9287
9307
  * "timestamp": "2026-04-20T12:00:00.000Z",
9288
9308
  * "path": "/api/v1/nodes",
9289
9309
  * "method": "GET"
@@ -9449,9 +9469,14 @@ interface operations {
9449
9469
  };
9450
9470
  ApiNodesController_listNodeParents: {
9451
9471
  parameters: {
9452
- query?: never;
9472
+ query?: {
9473
+ /** @description Page number (1-based) */
9474
+ page?: number;
9475
+ /** @description Items per page (1-100, default 20) */
9476
+ take?: number;
9477
+ };
9453
9478
  header?: {
9454
- /** @description An `ETag` from a previous response. Answers `304 Not Modified` when the hierarchy has not changed since, so a client holding a cached tree can revalidate on a short interval without re-reading it. */
9479
+ /** @description An `ETag` from a previous response for the same page and query. Answers `304 Not Modified` when the hierarchy has not changed since, so a client holding a cached copy can revalidate on a short interval without re-reading it. */
9455
9480
  "If-None-Match"?: string;
9456
9481
  };
9457
9482
  path?: never;
@@ -9459,7 +9484,7 @@ interface operations {
9459
9484
  };
9460
9485
  requestBody?: never;
9461
9486
  responses: {
9462
- /** @description Parent edges returned */
9487
+ /** @description One page of parent edges, by node id */
9463
9488
  200: {
9464
9489
  headers: {
9465
9490
  [name: string]: unknown;
@@ -9467,17 +9492,18 @@ interface operations {
9467
9492
  content: {
9468
9493
  "application/json": {
9469
9494
  items: components["schemas"]["NodeParentEdgeResponseDto"][];
9495
+ pagination: components["schemas"]["PageMetaDto"];
9470
9496
  };
9471
9497
  };
9472
9498
  };
9473
- /** @description The hierarchy is unchanged since the supplied `ETag`. No body; keep using the cached tree. */
9499
+ /** @description The hierarchy is unchanged since the supplied `ETag`. No body; keep using the cached copy. */
9474
9500
  304: {
9475
9501
  headers: {
9476
9502
  [name: string]: unknown;
9477
9503
  };
9478
9504
  content?: never;
9479
9505
  };
9480
- /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
9506
+ /** @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 */
9481
9507
  400: {
9482
9508
  headers: {
9483
9509
  [name: string]: unknown;
@@ -9488,7 +9514,7 @@ interface operations {
9488
9514
  * "error": {
9489
9515
  * "statusCode": 400,
9490
9516
  * "code": null,
9491
- * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
9517
+ * "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",
9492
9518
  * "timestamp": "2026-04-20T12:00:00.000Z",
9493
9519
  * "path": "/api/v1/nodes/parents",
9494
9520
  * "method": "GET"
@@ -9577,7 +9603,7 @@ interface operations {
9577
9603
  * "code": null,
9578
9604
  * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
9579
9605
  * "timestamp": "2026-04-20T12:00:00.000Z",
9580
- * "path": "/api/v1/nodes",
9606
+ * "path": "/api/v1/nodes/{id}",
9581
9607
  * "method": "GET"
9582
9608
  * }
9583
9609
  * }
@@ -9918,7 +9944,18 @@ interface operations {
9918
9944
  };
9919
9945
  ApiNodesController_getSubtree: {
9920
9946
  parameters: {
9921
- query?: never;
9947
+ query?: {
9948
+ /** @description Page number (1-based) */
9949
+ page?: number;
9950
+ /** @description Items per page (1-100, default 20) */
9951
+ take?: number;
9952
+ /** @description Search node names and slugs */
9953
+ q?: string;
9954
+ /** @description Sort column. Defaults to `created`, oldest first. */
9955
+ sort_by?: "name" | "created";
9956
+ /** @description Sort direction */
9957
+ order?: "asc" | "desc";
9958
+ };
9922
9959
  header?: never;
9923
9960
  path: {
9924
9961
  id: string;
@@ -9927,18 +9964,19 @@ interface operations {
9927
9964
  };
9928
9965
  requestBody?: never;
9929
9966
  responses: {
9930
- /** @description Subtree returned */
9967
+ /** @description One page of the node and its descendants in scope */
9931
9968
  200: {
9932
9969
  headers: {
9933
9970
  [name: string]: unknown;
9934
9971
  };
9935
9972
  content: {
9936
9973
  "application/json": {
9937
- data: components["schemas"]["HierarchyTreeNodeDto"];
9974
+ items: components["schemas"]["ScopedNodeResponseDto"][];
9975
+ pagination: components["schemas"]["PageMetaDto"];
9938
9976
  };
9939
9977
  };
9940
9978
  };
9941
- /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
9979
+ /** @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 */
9942
9980
  400: {
9943
9981
  headers: {
9944
9982
  [name: string]: unknown;
@@ -9949,9 +9987,9 @@ interface operations {
9949
9987
  * "error": {
9950
9988
  * "statusCode": 400,
9951
9989
  * "code": null,
9952
- * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
9990
+ * "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",
9953
9991
  * "timestamp": "2026-04-20T12:00:00.000Z",
9954
- * "path": "/api/v1/nodes",
9992
+ * "path": "/api/v1/nodes/{id}/tree",
9955
9993
  * "method": "GET"
9956
9994
  * }
9957
9995
  * }
@@ -10038,7 +10076,7 @@ interface operations {
10038
10076
  * "code": null,
10039
10077
  * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
10040
10078
  * "timestamp": "2026-04-20T12:00:00.000Z",
10041
- * "path": "/api/v1/nodes",
10079
+ * "path": "/api/v1/nodes/{id}",
10042
10080
  * "method": "GET"
10043
10081
  * }
10044
10082
  * }
@@ -10092,7 +10130,18 @@ interface operations {
10092
10130
  };
10093
10131
  ApiNodesController_getChildren: {
10094
10132
  parameters: {
10095
- query?: never;
10133
+ query?: {
10134
+ /** @description Page number (1-based) */
10135
+ page?: number;
10136
+ /** @description Items per page (1-100, default 20) */
10137
+ take?: number;
10138
+ /** @description Search node names and slugs */
10139
+ q?: string;
10140
+ /** @description Sort column. Defaults to `created`, oldest first. */
10141
+ sort_by?: "name" | "created";
10142
+ /** @description Sort direction */
10143
+ order?: "asc" | "desc";
10144
+ };
10096
10145
  header?: never;
10097
10146
  path: {
10098
10147
  id: string;
@@ -10101,7 +10150,7 @@ interface operations {
10101
10150
  };
10102
10151
  requestBody?: never;
10103
10152
  responses: {
10104
- /** @description Children returned */
10153
+ /** @description One page of the node's children */
10105
10154
  200: {
10106
10155
  headers: {
10107
10156
  [name: string]: unknown;
@@ -10109,10 +10158,11 @@ interface operations {
10109
10158
  content: {
10110
10159
  "application/json": {
10111
10160
  items: components["schemas"]["NodeResponseDto"][];
10161
+ pagination: components["schemas"]["PageMetaDto"];
10112
10162
  };
10113
10163
  };
10114
10164
  };
10115
- /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
10165
+ /** @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 */
10116
10166
  400: {
10117
10167
  headers: {
10118
10168
  [name: string]: unknown;
@@ -10123,9 +10173,9 @@ interface operations {
10123
10173
  * "error": {
10124
10174
  * "statusCode": 400,
10125
10175
  * "code": null,
10126
- * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
10176
+ * "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",
10127
10177
  * "timestamp": "2026-04-20T12:00:00.000Z",
10128
- * "path": "/api/v1/nodes",
10178
+ * "path": "/api/v1/nodes/{id}/children",
10129
10179
  * "method": "GET"
10130
10180
  * }
10131
10181
  * }
@@ -10557,10 +10607,10 @@ interface operations {
10557
10607
  page?: number;
10558
10608
  /** @description Items per page (1-100, default 20) */
10559
10609
  take?: number;
10560
- /** @description Search term */
10610
+ /** @description Search organization names and slugs */
10561
10611
  q?: string;
10562
- /** @description Column to sort by. Allowed values depend on the endpoint. */
10563
- sort_by?: string;
10612
+ /** @description Sort column. Defaults to `name`, A to Z. */
10613
+ sort_by?: "name" | "created";
10564
10614
  /** @description Sort direction */
10565
10615
  order?: "asc" | "desc";
10566
10616
  /** @description Exact match on the organization's `external_id` (your own id for it). Answers one organization or none. */
@@ -12634,10 +12684,10 @@ interface operations {
12634
12684
  page?: number;
12635
12685
  /** @description Items per page (1-100, default 20) */
12636
12686
  take?: number;
12637
- /** @description Search term */
12687
+ /** @description Search member names and emails */
12638
12688
  q?: string;
12639
- /** @description Column to sort by. Allowed values depend on the endpoint. */
12640
- sort_by?: string;
12689
+ /** @description Sort column. Defaults to `created`, oldest membership first. */
12690
+ sort_by?: "name" | "email" | "role" | "created";
12641
12691
  /** @description Sort direction */
12642
12692
  order?: "asc" | "desc";
12643
12693
  /** @description Only members holding this role */
@@ -12819,7 +12869,7 @@ interface operations {
12819
12869
  "application/json": components["schemas"]["ErrorResponseDto"];
12820
12870
  };
12821
12871
  };
12822
- /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
12872
+ /** @description The caller is an organization administrator signed in as an identity and holds no `rbac.manage_assignments` at the organization; an organization administrator adds people by invitation (`organization.member_add_requires_invite`). Also a caller without the permissions the route needs */
12823
12873
  403: {
12824
12874
  headers: {
12825
12875
  [name: string]: unknown;
@@ -12830,10 +12880,10 @@ interface operations {
12830
12880
  * "error": {
12831
12881
  * "statusCode": 403,
12832
12882
  * "code": null,
12833
- * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
12883
+ * "message": "The caller is an organization administrator signed in as an identity and holds no `rbac.manage_assignments` at the organization; an organization administrator adds people by invitation (`organization.member_add_requires_invite`). Also a caller without the permissions the route needs",
12834
12884
  * "timestamp": "2026-04-20T12:00:00.000Z",
12835
- * "path": "/api/v1/organizations",
12836
- * "method": "GET"
12885
+ * "path": "/api/v1/organizations/{id}/members",
12886
+ * "method": "POST"
12837
12887
  * }
12838
12888
  * }
12839
12889
  */
@@ -13156,7 +13206,7 @@ interface operations {
13156
13206
  };
13157
13207
  requestBody?: never;
13158
13208
  responses: {
13159
- /** @description Factors, recovery codes and trusted devices cleared; the member enrols again at their next sign-in */
13209
+ /** @description Factors and recovery codes cleared, and the devices trusted in this Environment; the member enrols again at their next sign-in */
13160
13210
  204: {
13161
13211
  headers: {
13162
13212
  [name: string]: unknown;
@@ -13247,7 +13297,7 @@ interface operations {
13247
13297
  "application/json": components["schemas"]["ErrorResponseDto"];
13248
13298
  };
13249
13299
  };
13250
- /** @description The caller is an organization administrator and the member also belongs to another organization in the Environment; the second factor is held once per identity, so only the application's administrators may reset it (`organization.member_mfa_shared`) */
13300
+ /** @description The caller is an organization administrator and the member also belongs to another organization, or holds an active membership in another Environment of the Account; the second factor is held once per identity, so only the application's administrators may reset it (`organization.member_mfa_shared`) */
13251
13301
  409: {
13252
13302
  headers: {
13253
13303
  [name: string]: unknown;
@@ -13258,7 +13308,7 @@ interface operations {
13258
13308
  * "error": {
13259
13309
  * "statusCode": 409,
13260
13310
  * "code": null,
13261
- * "message": "The caller is an organization administrator and the member also belongs to another organization in the Environment; the second factor is held once per identity, so only the application's administrators may reset it (`organization.member_mfa_shared`)",
13311
+ * "message": "The caller is an organization administrator and the member also belongs to another organization, or holds an active membership in another Environment of the Account; the second factor is held once per identity, so only the application's administrators may reset it (`organization.member_mfa_shared`)",
13262
13312
  * "timestamp": "2026-04-20T12:00:00.000Z",
13263
13313
  * "path": "/api/v1/organizations/{id}/members/{identityId}/mfa/reset",
13264
13314
  * "method": "POST"
@@ -13279,11 +13329,11 @@ interface operations {
13279
13329
  take?: number;
13280
13330
  /** @description Search term */
13281
13331
  q?: string;
13282
- /** @description Column to sort by. Allowed values depend on the endpoint. */
13283
- sort_by?: string;
13332
+ /** @description Column to sort by. Defaults to `created`, newest first. */
13333
+ sort_by?: "name" | "email" | "created";
13284
13334
  /** @description Sort direction */
13285
13335
  order?: "asc" | "desc";
13286
- /** @description Filter by invitation status */
13336
+ /** @description Filter by invite status */
13287
13337
  status?: "pending" | "accepted" | "revoked" | "expired";
13288
13338
  };
13289
13339
  header?: never;
@@ -16145,7 +16195,18 @@ interface operations {
16145
16195
  };
16146
16196
  ApiOrganizationDirectoryGroupsController_list: {
16147
16197
  parameters: {
16148
- query?: never;
16198
+ query?: {
16199
+ /** @description Page number (1-based) */
16200
+ page?: number;
16201
+ /** @description Items per page (1-100, default 20) */
16202
+ take?: number;
16203
+ /** @description Search group display names and external ids */
16204
+ q?: string;
16205
+ /** @description Sort column. Defaults to `name`, A to Z. */
16206
+ sort_by?: "name" | "created";
16207
+ /** @description Sort direction */
16208
+ order?: "asc" | "desc";
16209
+ };
16149
16210
  header?: never;
16150
16211
  path: {
16151
16212
  id: string;
@@ -16154,7 +16215,7 @@ interface operations {
16154
16215
  };
16155
16216
  requestBody?: never;
16156
16217
  responses: {
16157
- /** @description Pushed groups returned, each with its role mapping and member count */
16218
+ /** @description One page of pushed groups, each with its role mapping and member count, by display name unless sorted (`sort_by` `name` or `created`); `q` searches display names and external ids */
16158
16219
  200: {
16159
16220
  headers: {
16160
16221
  [name: string]: unknown;
@@ -16162,6 +16223,7 @@ interface operations {
16162
16223
  content: {
16163
16224
  "application/json": {
16164
16225
  items: components["schemas"]["ScimGroupResponseDto"][];
16226
+ pagination: components["schemas"]["PageMetaDto"];
16165
16227
  };
16166
16228
  };
16167
16229
  };
@@ -19307,10 +19369,10 @@ interface operations {
19307
19369
  page?: number;
19308
19370
  /** @description Items per page (1-100, default 20) */
19309
19371
  take?: number;
19310
- /** @description Search term */
19372
+ /** @description Search the endpoint URL */
19311
19373
  q?: string;
19312
- /** @description Column to sort by. Allowed values depend on the endpoint. */
19313
- sort_by?: string;
19374
+ /** @description Sort column. Defaults to `created`, newest first. */
19375
+ sort_by?: "url" | "created";
19314
19376
  /** @description Sort direction */
19315
19377
  order?: "asc" | "desc";
19316
19378
  };
@@ -19578,10 +19640,10 @@ interface operations {
19578
19640
  page?: number;
19579
19641
  /** @description Items per page (1-100, default 20) */
19580
19642
  take?: number;
19581
- /** @description Search term */
19643
+ /** @description Search the event type */
19582
19644
  q?: string;
19583
- /** @description Column to sort by. Allowed values depend on the endpoint. */
19584
- sort_by?: string;
19645
+ /** @description Sort column. Defaults to `created`, newest first. */
19646
+ sort_by?: "created" | "event_type" | "status";
19585
19647
  /** @description Sort direction */
19586
19648
  order?: "asc" | "desc";
19587
19649
  };
@@ -20022,10 +20084,10 @@ interface operations {
20022
20084
  page?: number;
20023
20085
  /** @description Items per page (1-100, default 20) */
20024
20086
  take?: number;
20025
- /** @description Search term */
20087
+ /** @description Search client names */
20026
20088
  q?: string;
20027
- /** @description Column to sort by. Allowed values depend on the endpoint. */
20028
- sort_by?: string;
20089
+ /** @description Sort column. Defaults to `created`, newest first. */
20090
+ sort_by?: "name" | "created";
20029
20091
  /** @description Sort direction */
20030
20092
  order?: "asc" | "desc";
20031
20093
  };
@@ -20136,7 +20198,7 @@ interface operations {
20136
20198
  };
20137
20199
  };
20138
20200
  };
20139
- /** @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 */
20201
+ /** @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, `initiate_login_uri` is malformed or not `https` (loopback hosts excepted), or `scopes` names a scope Canopy does not issue (`oauth.client_scope_unknown`); or the request sent both an `X-API-Key` and an `Authorization` header */
20140
20202
  400: {
20141
20203
  headers: {
20142
20204
  [name: string]: unknown;
@@ -20147,7 +20209,7 @@ interface operations {
20147
20209
  * "error": {
20148
20210
  * "statusCode": 400,
20149
20211
  * "code": null,
20150
- * "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",
20212
+ * "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, `initiate_login_uri` is malformed or not `https` (loopback hosts excepted), or `scopes` names a scope Canopy does not issue (`oauth.client_scope_unknown`); or the request sent both an `X-API-Key` and an `Authorization` header",
20151
20213
  * "timestamp": "2026-04-20T12:00:00.000Z",
20152
20214
  * "path": "/api/v1/oauth-clients",
20153
20215
  * "method": "POST"
@@ -20547,7 +20609,7 @@ interface operations {
20547
20609
  };
20548
20610
  };
20549
20611
  };
20550
- /** @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 */
20612
+ /** @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, `initiate_login_uri` is malformed or not `https` (loopback hosts excepted), or `scopes` names a scope Canopy does not issue (`oauth.client_scope_unknown`); or the request sent both an `X-API-Key` and an `Authorization` header */
20551
20613
  400: {
20552
20614
  headers: {
20553
20615
  [name: string]: unknown;
@@ -20558,7 +20620,7 @@ interface operations {
20558
20620
  * "error": {
20559
20621
  * "statusCode": 400,
20560
20622
  * "code": null,
20561
- * "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",
20623
+ * "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, `initiate_login_uri` is malformed or not `https` (loopback hosts excepted), or `scopes` names a scope Canopy does not issue (`oauth.client_scope_unknown`); or the request sent both an `X-API-Key` and an `Authorization` header",
20562
20624
  * "timestamp": "2026-04-20T12:00:00.000Z",
20563
20625
  * "path": "/api/v1/oauth-clients/{id}",
20564
20626
  * "method": "PATCH"
@@ -20748,10 +20810,10 @@ interface operations {
20748
20810
  page?: number;
20749
20811
  /** @description Items per page (1-100, default 20) */
20750
20812
  take?: number;
20751
- /** @description Search term */
20813
+ /** @description Search key names */
20752
20814
  q?: string;
20753
- /** @description Column to sort by. Allowed values depend on the endpoint. */
20754
- sort_by?: string;
20815
+ /** @description Sort column. Defaults to `created`, newest first. */
20816
+ sort_by?: "name" | "created";
20755
20817
  /** @description Sort direction */
20756
20818
  order?: "asc" | "desc";
20757
20819
  };
@@ -21050,7 +21112,7 @@ interface operations {
21050
21112
  "application/json": components["schemas"]["ErrorResponseDto"];
21051
21113
  };
21052
21114
  };
21053
- /** @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 */
21115
+ /** @description The caller lacks `api_key.manage` (a scoped API key without that scope, or an admin without the Account capability that covers it), or is a scoped API key acting on a key with more access than its own: a `full_access` key, or one holding a scope outside its own (`api_key.access_exceeds_caller`) */
21054
21116
  403: {
21055
21117
  headers: {
21056
21118
  [name: string]: unknown;
@@ -21061,10 +21123,10 @@ interface operations {
21061
21123
  * "error": {
21062
21124
  * "statusCode": 403,
21063
21125
  * "code": null,
21064
- * "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",
21126
+ * "message": "The caller lacks `api_key.manage` (a scoped API key without that scope, or an admin without the Account capability that covers it), or is a scoped API key acting on a key with more access than its own: a `full_access` key, or one holding a scope outside its own (`api_key.access_exceeds_caller`)",
21065
21127
  * "timestamp": "2026-04-20T12:00:00.000Z",
21066
- * "path": "/api/v1/api-keys",
21067
- * "method": "GET"
21128
+ * "path": "/api/v1/api-keys/{id}",
21129
+ * "method": "DELETE"
21068
21130
  * }
21069
21131
  * }
21070
21132
  */
@@ -21162,7 +21224,7 @@ interface operations {
21162
21224
  "application/json": components["schemas"]["ErrorResponseDto"];
21163
21225
  };
21164
21226
  };
21165
- /** @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 */
21227
+ /** @description The caller lacks `api_key.manage` (a scoped API key without that scope, or an admin without the Account capability that covers it), or is a scoped API key acting on a key with more access than its own: a `full_access` key, or one holding a scope outside its own (`api_key.access_exceeds_caller`) */
21166
21228
  403: {
21167
21229
  headers: {
21168
21230
  [name: string]: unknown;
@@ -21173,10 +21235,10 @@ interface operations {
21173
21235
  * "error": {
21174
21236
  * "statusCode": 403,
21175
21237
  * "code": null,
21176
- * "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",
21238
+ * "message": "The caller lacks `api_key.manage` (a scoped API key without that scope, or an admin without the Account capability that covers it), or is a scoped API key acting on a key with more access than its own: a `full_access` key, or one holding a scope outside its own (`api_key.access_exceeds_caller`)",
21177
21239
  * "timestamp": "2026-04-20T12:00:00.000Z",
21178
- * "path": "/api/v1/api-keys",
21179
- * "method": "GET"
21240
+ * "path": "/api/v1/api-keys/{id}",
21241
+ * "method": "PATCH"
21180
21242
  * }
21181
21243
  * }
21182
21244
  */
@@ -21270,7 +21332,7 @@ interface operations {
21270
21332
  "application/json": components["schemas"]["ErrorResponseDto"];
21271
21333
  };
21272
21334
  };
21273
- /** @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 */
21335
+ /** @description The caller lacks `api_key.manage` (a scoped API key without that scope, or an admin without the Account capability that covers it), or is a scoped API key acting on a key with more access than its own: a `full_access` key, or one holding a scope outside its own (`api_key.access_exceeds_caller`) */
21274
21336
  403: {
21275
21337
  headers: {
21276
21338
  [name: string]: unknown;
@@ -21281,10 +21343,10 @@ interface operations {
21281
21343
  * "error": {
21282
21344
  * "statusCode": 403,
21283
21345
  * "code": null,
21284
- * "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",
21346
+ * "message": "The caller lacks `api_key.manage` (a scoped API key without that scope, or an admin without the Account capability that covers it), or is a scoped API key acting on a key with more access than its own: a `full_access` key, or one holding a scope outside its own (`api_key.access_exceeds_caller`)",
21285
21347
  * "timestamp": "2026-04-20T12:00:00.000Z",
21286
- * "path": "/api/v1/api-keys",
21287
- * "method": "GET"
21348
+ * "path": "/api/v1/api-keys/{id}/rotate-secret",
21349
+ * "method": "POST"
21288
21350
  * }
21289
21351
  * }
21290
21352
  */
@@ -21479,8 +21541,16 @@ declare class Identities {
21479
21541
  * newest first: when and where it was signed in, when it expires, and the
21480
21542
  * organization it is acting in. Read it back after a revoke to confirm,
21481
21543
  * from your own side, that a sign-out took.
21544
+ *
21545
+ * Paginated (20 per page by default, `take` up to 100), so this returns a
21546
+ * `Paginator`: iterate it for every session, or call `.first()` for the
21547
+ * newest. The list takes `page` and `take` only; its order is fixed.
21548
+ *
21549
+ * ```ts
21550
+ * for await (const session of canopy.identities.sessions(id)) { … }
21551
+ * ```
21482
21552
  */
21483
- sessions(id: string): Promise<ResponseBody<"ApiIdentitiesController_listIdentitySessions">>;
21553
+ sessions(id: string, query?: QueryParams<"ApiIdentitiesController_listIdentitySessions">): Paginator<IdentitySessionItem>;
21484
21554
  /**
21485
21555
  * Ends one session and leaves the identity's others signed in. `sessionId`
21486
21556
  * is the session's `id` from `sessions`: its current refresh token, which
@@ -21608,8 +21678,18 @@ declare class Organizations {
21608
21678
  revokeDirectoryToken(id: string, tokenId: string): Promise<void>;
21609
21679
  /** The organization's own provisioning events, newest first. */
21610
21680
  listDirectoryActivity(id: string): Promise<ResponseBody<"ApiOrganizationDirectoryController_activity">>;
21611
- /** The groups the provider has pushed, each with its role mapping. */
21612
- listDirectoryGroups(id: string): Promise<ResponseBody<"ApiOrganizationDirectoryGroupsController_list">>;
21681
+ /**
21682
+ * The groups the provider has pushed, each with its role mapping.
21683
+ *
21684
+ * Paginated (20 per page by default, `take` up to 100), so this returns a
21685
+ * `Paginator`. Sorted by display name unless `sort_by: "created"`; `q`
21686
+ * searches display names and external ids.
21687
+ *
21688
+ * ```ts
21689
+ * for await (const group of canopy.organizations.listDirectoryGroups(id)) { … }
21690
+ * ```
21691
+ */
21692
+ listDirectoryGroups(id: string, query?: QueryParams<"ApiOrganizationDirectoryGroupsController_list">): Paginator<OrganizationDirectoryGroupItem>;
21613
21693
  /**
21614
21694
  * Grant a listed role to every member of a pushed group, at the
21615
21695
  * organization. A role not on the organization's list is refused with
@@ -21622,6 +21702,8 @@ declare class Organizations {
21622
21702
  type OrganizationItem = ItemOf$2<ResponseBody<"ApiOrganizationsController_listOrganizations">>;
21623
21703
  type OrganizationMemberItem = ItemOf$2<ResponseBody<"ApiOrganizationsController_listMembers">>;
21624
21704
  type OrganizationInviteItem = ItemOf$2<ResponseBody<"ApiOrganizationsController_listInvites">>;
21705
+ /** One pushed group from an organization's directory. */
21706
+ type OrganizationDirectoryGroupItem = ItemOf$2<ResponseBody<"ApiOrganizationDirectoryGroupsController_list">>;
21625
21707
  type ItemOf$2<T> = T extends {
21626
21708
  items: (infer Item)[];
21627
21709
  } ? Item : never;
@@ -21655,6 +21737,10 @@ declare class Permissions {
21655
21737
  *
21656
21738
  * Prefer this to a loop over `evaluate` when rendering a screen: the checks
21657
21739
  * are answered together instead of paying request latency for each.
21740
+ *
21741
+ * One request carries between 1 and 100 checks. More is refused with a
21742
+ * `400` (`CanopyError`, `statusCode` 400) and nothing is evaluated, so split
21743
+ * a larger set into batches of 100.
21658
21744
  */
21659
21745
  evaluateBulk(input: RequestBody<"ApiPermissionsController_evaluateBulk">, options?: CallOptions): Promise<ResponseBody<"ApiPermissionsController_evaluateBulk">>;
21660
21746
  /**
@@ -21792,10 +21878,18 @@ interface LocalAuthorizationQuery {
21792
21878
  node_id?: string;
21793
21879
  }
21794
21880
  interface LocalAuthorizerStats {
21795
- /** Calls made to read an identity's grant roots. */
21881
+ /** Reads of an identity's grant roots, one per refresh however many pages it took. */
21796
21882
  grantFetches: number;
21797
- /** Calls made to read the hierarchy, including revalidations. */
21883
+ /** Page requests those reads made: at least one per read, one more per further 100 grants. */
21884
+ grantPages: number;
21885
+ /** Reads of the hierarchy, one per refresh, including revalidations. */
21798
21886
  treeRequests: number;
21887
+ /**
21888
+ * Page requests those reads made: one for a revalidation the server answers
21889
+ * `304`, otherwise one per page of 100 nodes, plus the request that confirms
21890
+ * a walk of several pages was not torn by a change made during it.
21891
+ */
21892
+ treePages: number;
21799
21893
  /** Revalidations the server answered `304`, so no tree was transferred. */
21800
21894
  treeNotModified: number;
21801
21895
  }
@@ -21859,14 +21953,39 @@ declare class LocalAuthorizer {
21859
21953
  /** Climb from `nodeId` and look for a grant root among its ancestors. */
21860
21954
  private holdsAtNode;
21861
21955
  private grantRootsFor;
21956
+ /**
21957
+ * Every page of the identity's grant roots, folded into permission → nodes.
21958
+ *
21959
+ * Each row is one permission at one node, so a permission granted at three
21960
+ * nodes arrives as three rows, possibly on different pages. Stopping after
21961
+ * the first page would under-report what the identity holds: a false deny,
21962
+ * the safe direction, but a wrong answer all the same.
21963
+ */
21862
21964
  private fetchGrantRoots;
21863
21965
  private parents;
21864
21966
  /**
21865
21967
  * Revalidate rather than re-read. The hierarchy is the expensive half and
21866
21968
  * the one that changes least, so the common case is a `304` and no transfer
21867
21969
  * at all — the tree stays in memory and only its expiry moves.
21970
+ *
21971
+ * The edges come a page at a time, so only the first page is conditional:
21972
+ * its validator covers the whole hierarchy, and a `304` to it means no page
21973
+ * has changed. On a `200` the remaining pages are read plainly and the map
21974
+ * is rebuilt from every page.
21975
+ *
21976
+ * A walk over several pages is not one snapshot. A node added or removed
21977
+ * between two page reads shifts the rows under the offset, so a row can be
21978
+ * skipped, which would leave a node out of the map until the next refresh.
21979
+ * So the walk is confirmed by asking for the first page again with the
21980
+ * validator it came with: a `304` proves nothing changed while the pages
21981
+ * were read. A `200` is a fresh first page, and the walk starts again from
21982
+ * it, up to {@link MAX_TREE_WALKS} times.
21868
21983
  */
21869
21984
  private fetchTree;
21985
+ private parentsFirstPage;
21986
+ /** The first page's edges followed by every later page's. */
21987
+ private parentsRemainingPages;
21988
+ private keepTree;
21870
21989
  }
21871
21990
 
21872
21991
  /**
@@ -21964,8 +22083,9 @@ declare class CanopyConnectionError extends Error {
21964
22083
  * whole point of verifying a signature rather than calling an endpoint.
21965
22084
  *
21966
22085
  * Branch on `code`; it follows the same dot-notation contract as the API's own
21967
- * codes. Every one of them means the same thing to an HTTP caller — 401 — so
21968
- * the code is for your logs and your tests, not usually for the response.
22086
+ * codes. Every one but `token.jwks_unavailable` means the same thing to an
22087
+ * HTTP caller, 401; that one means the keys could not be read, so the token may
22088
+ * be good and the answer is 503. {@link tokenErrorStatus} maps them.
21969
22089
  */
21970
22090
  declare class CanopyTokenError extends Error {
21971
22091
  readonly name = "CanopyTokenError";
@@ -21982,6 +22102,8 @@ declare class CanopyTokenError extends Error {
21982
22102
  * - `token.audience_mismatch` — `aud` does not include the configured audience
21983
22103
  * - `token.audience_unverified` — token has an `aud` but none was configured
21984
22104
  * - `token.preauth_not_allowed` — a pre-auth token, which grants no access
22105
+ * - `token.type_not_allowed` — a principal type the verifier does not accept
22106
+ * (see `allowedTypes`)
21985
22107
  */
21986
22108
  readonly code: string;
21987
22109
  constructor(code: string, message: string, options?: {
@@ -22013,6 +22135,44 @@ declare function isCanopyError(error: unknown): error is CanopyError;
22013
22135
  declare function isCanopyConnectionError(error: unknown): error is CanopyConnectionError;
22014
22136
  declare function isCanopyTokenError(error: unknown): error is CanopyTokenError;
22015
22137
 
22138
+ /**
22139
+ * The HTTP answer a failure should become, for code that verifies tokens or
22140
+ * authorizes requests outside the NestJS guards (Express, Fastify, a worker).
22141
+ * The guards use the same mapping, so every integration answers alike.
22142
+ */
22143
+ interface FailureStatus {
22144
+ status: number;
22145
+ /** A message safe to send to the caller; the detail stays on the error. */
22146
+ message: string;
22147
+ }
22148
+ /**
22149
+ * The answer for a failed {@link TokenVerifier.verify}: `401` when the token is
22150
+ * at fault, `503` when the signing keys could not be read and the token may be
22151
+ * perfectly good.
22152
+ *
22153
+ * The difference matters. A client reads `401` as "your token is stale",
22154
+ * discards a valid one and asks for another, which aims a refresh storm at an
22155
+ * issuer that is already down, and an outage that only emits 4xx is invisible
22156
+ * to anything watching for 5xx.
22157
+ *
22158
+ * Anything that is not a token error is returned as `500`: it is a bug, not a
22159
+ * verdict on the token.
22160
+ */
22161
+ declare function tokenErrorStatus(error: unknown): FailureStatus;
22162
+ /**
22163
+ * The answer for a failed authorization check ({@link LocalAuthorizer.evaluate}
22164
+ * or a {@link Canopy} call that decides access). Every branch denies; they say
22165
+ * different things so an incident is diagnosable:
22166
+ *
22167
+ * - `500` when the authorizer cannot see far enough to decide (a credential
22168
+ * that cannot read the hierarchy), when Canopy rejected our own credential,
22169
+ * when the endpoint is not served (an SDK newer than the API), or on a 4xx
22170
+ * nobody anticipated. No retry fixes these.
22171
+ * - `503` when Canopy did not answer, or answered 429 or 5xx.
22172
+ * - `403` when Canopy answered that the identity is not in this Environment.
22173
+ */
22174
+ declare function authorizationErrorStatus(error: unknown): FailureStatus;
22175
+
22016
22176
  interface TokenVerifierOptions {
22017
22177
  /**
22018
22178
  * The Environment whose tokens are accepted. Every Environment is its own
@@ -22070,6 +22230,16 @@ interface TokenVerifierOptions {
22070
22230
  * request path, so an unbounded read there is an unbounded request.
22071
22231
  */
22072
22232
  jwksTimeoutMs?: number;
22233
+ /**
22234
+ * The principal types accepted, matched against the `type` claim. Defaults to
22235
+ * `["identity"]`: the people who sign in to your application.
22236
+ *
22237
+ * Canopy also signs tokens for its own administrators (`user`), its staff
22238
+ * (`platform`) and, for some flows, API keys (`api_key`), all with the same
22239
+ * keys and issuer. A backend that serves your end users should accept none
22240
+ * of them, so they are refused unless you name them here.
22241
+ */
22242
+ allowedTypes?: ReadonlyArray<CanopyTokenClaims["type"]>;
22073
22243
  /** Injectable for tests and for runtimes with a non-global fetch. */
22074
22244
  fetch?: typeof globalThis.fetch;
22075
22245
  }
@@ -22160,11 +22330,14 @@ declare class TokenVerifier {
22160
22330
  private readonly jwksTimeoutMs;
22161
22331
  private readonly clockToleranceSec;
22162
22332
  private readonly allowPreAuthTokens;
22333
+ private readonly allowedTypes;
22163
22334
  private readonly fetchImpl;
22164
22335
  /** Imported keys by `kid`, so a repeat verification skips the import cost. */
22165
22336
  private keys;
22166
22337
  private keysFetchedAt;
22167
22338
  private lastFetchAttemptAt;
22339
+ /** Whether the latest read of the key set failed, for an unknown `kid`. */
22340
+ private lastFetchFailed;
22168
22341
  /** In-flight fetch, so a burst of requests triggers one call, not N. */
22169
22342
  private inFlight;
22170
22343
  constructor(options?: TokenVerifierOptions);
@@ -22208,6 +22381,7 @@ declare class TokenVerifier {
22208
22381
  private shouldRefresh;
22209
22382
  private refreshKeys;
22210
22383
  private fetchKeys;
22384
+ private readKeys;
22211
22385
  }
22212
22386
 
22213
22387
  /**
@@ -22254,4 +22428,4 @@ type WebhookEventData<Name extends WebhookEventName> = WebhookEvent<Name>["data"
22254
22428
  */
22255
22429
  declare function isWebhookEvent<Name extends WebhookEventName>(delivery: WebhookDelivery, name: Name): delivery is WebhookEvent<Name>;
22256
22430
 
22257
- 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 };
22431
+ 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, type FailureStatus, Identities, type IdentityAssignmentItem, type IdentityItem, type IdentitySessionItem, type LocalAuthorizationQuery, LocalAuthorizer, type LocalAuthorizerOptions, type LocalAuthorizerStats, MAX_TTL_MS, type OffsetPagination, type OperationId, type OrganizationDirectoryGroupItem, 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, authorizationErrorStatus, type components, isCanopyAuthorizerError, isCanopyConnectionError, isCanopyError, isCanopyTokenError, isCursorPagination, isWebhookEvent, type operations, orgContext, paginate, type paths, tokenErrorStatus, withConcurrency };