@canopy-io/node 0.10.0 → 0.12.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
@@ -748,7 +748,7 @@ interface paths {
748
748
  };
749
749
  /**
750
750
  * Get identity's effective permissions
751
- * @description Returns the identity's effective Application-wide permission keys for the current Environment as a flat `items` array of strings, resolved across all of its role assignments. Use this to answer "what can this identity do" without replaying individual assignments. Returns `404` when the identity has no membership in this Environment.
751
+ * @description Returns the identity's effective permission keys for the current Environment as a flat `items` array of strings. Without `node_id`, the Application-wide answer: every permission its role assignments grant anywhere. With `node_id`, the answer at that node: the permissions granted by assignments on the node's lineage, the list a screen renders its controls from. Returns `404` when the identity has no membership in this Environment, or when `node_id` names no node in it.
752
752
  */
753
753
  get: operations["ApiIdentitiesController_getIdentityPermissions"];
754
754
  put?: never;
@@ -759,6 +759,26 @@ interface paths {
759
759
  patch?: never;
760
760
  trace?: never;
761
761
  };
762
+ "/api/v1/identities/{id}/accessible-nodes": {
763
+ parameters: {
764
+ query?: never;
765
+ header?: never;
766
+ path?: never;
767
+ cookie?: never;
768
+ };
769
+ /**
770
+ * Get where an identity may act with one permission
771
+ * @description Returns where the identity may act with `permission`, for a list query: `roots`, the nodes it holds the permission at that no other such node already covers, and `nodes`, every node beneath those roots, the roots included, when there are at most `max_nodes` of them (default 10,000; at most 50,000). Past the cap `nodes` is null and `complete` false, and the caller filters by `roots` against its own closure table or materialised path. `env_wide` is true when a root is the Environment's own root, so every node qualifies and no filter is needed; `nodes` is null then too. The same rules as `evaluate` decide the roots, so a list filtered by this answer agrees with the check a write makes. Returns `404` when the identity has no membership in this Environment.
772
+ */
773
+ get: operations["ApiIdentitiesController_getIdentityAccessibleNodes"];
774
+ put?: never;
775
+ post?: never;
776
+ delete?: never;
777
+ options?: never;
778
+ head?: never;
779
+ patch?: never;
780
+ trace?: never;
781
+ };
762
782
  "/api/v1/identities/{id}/grants": {
763
783
  parameters: {
764
784
  query?: never;
@@ -768,7 +788,7 @@ interface paths {
768
788
  };
769
789
  /**
770
790
  * Get where an identity holds each permission
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.
791
+ * @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. By default, assignments outside their effective window are excluded. With `include=windows`, every assignment is a row carrying `effective_from` and `effective_to` (null for an unbounded side), in effect or not, so a caller applies the window itself: it can say why a check fails (the grant has ended, or has not begun) and drop a grant at its boundary without reading again. Returns `404` when the identity has no membership in this Environment.
772
792
  */
773
793
  get: operations["ApiIdentitiesController_getIdentityGrants"];
774
794
  put?: never;
@@ -1075,6 +1095,170 @@ interface paths {
1075
1095
  patch?: never;
1076
1096
  trace?: never;
1077
1097
  };
1098
+ "/api/v1/organizations/{id}/me": {
1099
+ parameters: {
1100
+ query?: never;
1101
+ header?: never;
1102
+ path?: never;
1103
+ cookie?: never;
1104
+ };
1105
+ /**
1106
+ * What the caller administers in an organization
1107
+ * @description The authority read a customer's admin screen renders from: whether the caller holds `canopy:organization.manage` at the organization node (`administers_organization`), the topmost nodes where they hold `canopy:access.manage` inside it (`access_roots`, each with its name, type and the path of names from the organization down to it; the organization node itself when they administer the organization), the same for the structure and roles keys (empty until those ship), and whether the Environment's schema allows nodes beneath an organization (`has_hierarchy`). Computed from assignments at or beneath the organization node only, so a role held above every organization does not count. The developer's key answers as administering the whole organization. Refused with `403` for a caller holding nothing inside the organization.
1108
+ */
1109
+ get: operations["ApiOrganizationAccessController_me"];
1110
+ put?: never;
1111
+ post?: never;
1112
+ delete?: never;
1113
+ options?: never;
1114
+ head?: never;
1115
+ patch?: never;
1116
+ trace?: never;
1117
+ };
1118
+ "/api/v1/organizations/{id}/tree": {
1119
+ parameters: {
1120
+ query?: never;
1121
+ header?: never;
1122
+ path?: never;
1123
+ cookie?: never;
1124
+ };
1125
+ /**
1126
+ * List the organization's tree as the caller sees it
1127
+ * @description The organization's subtree pruned to the caller: every node beneath a node they administer is `accessible`, the ancestors between the organization node and such a node are `context_only`, and nothing else is returned. A paged flat list, each row carrying its parent, in the shape of the developer's node listing. Admitted to whoever the authority read admits.
1128
+ */
1129
+ get: operations["ApiOrganizationAccessController_tree"];
1130
+ put?: never;
1131
+ post?: never;
1132
+ delete?: never;
1133
+ options?: never;
1134
+ head?: never;
1135
+ patch?: never;
1136
+ trace?: never;
1137
+ };
1138
+ "/api/v1/organizations/{id}/nodes/{nodeId}/access": {
1139
+ parameters: {
1140
+ query?: never;
1141
+ header?: never;
1142
+ path?: never;
1143
+ cookie?: never;
1144
+ };
1145
+ /**
1146
+ * List who holds a role at a node in the organization
1147
+ * @description Who holds a role at the node, directly or inherited from a node above it inside the organization: one row per assignment with the identity, the role, where it was granted and its window. Paginated; filtered and sorted as the developer's node identities listing is. Requires `hierarchy.view` at the node, or `canopy:organization.manage` at the organization, or `canopy:access.manage` at the node or above it.
1148
+ */
1149
+ get: operations["ApiOrganizationAccessController_listAccess"];
1150
+ put?: never;
1151
+ post?: never;
1152
+ delete?: never;
1153
+ options?: never;
1154
+ head?: never;
1155
+ patch?: never;
1156
+ trace?: never;
1157
+ };
1158
+ "/api/v1/organizations/{id}/nodes/{nodeId}/access/summary": {
1159
+ parameters: {
1160
+ query?: never;
1161
+ header?: never;
1162
+ path?: never;
1163
+ cookie?: never;
1164
+ };
1165
+ /**
1166
+ * Summarize who holds a role at a node in the organization
1167
+ * @description The counts over the node's assignments: direct and inherited people, by status, roles in use and the most recent arrivals, with `can_manage_assignments` saying whether the caller may change them. Requires the same as the node access listing.
1168
+ */
1169
+ get: operations["ApiOrganizationAccessController_accessSummary"];
1170
+ put?: never;
1171
+ post?: never;
1172
+ delete?: never;
1173
+ options?: never;
1174
+ head?: never;
1175
+ patch?: never;
1176
+ trace?: never;
1177
+ };
1178
+ "/api/v1/organizations/{id}/nodes/{nodeId}/grantable-roles": {
1179
+ parameters: {
1180
+ query?: never;
1181
+ header?: never;
1182
+ path?: never;
1183
+ cookie?: never;
1184
+ };
1185
+ /**
1186
+ * List the roles the caller may grant at a node
1187
+ * @description The active, assignable roles of the Environment kept to the ones the caller may grant at the node under the grant ceiling: for an identity, those whose every permission it holds at the node or above; every assignable role for the developer's key and Console users. The list a picker offers, so nothing it shows is refused on write. Requires `canopy:access.manage` at the node or above it, `canopy:organization.manage` at the organization, or `hierarchy.manage` at the node. The response is an unpaginated `{ items }` array.
1188
+ */
1189
+ get: operations["ApiOrganizationAccessController_grantableRoles"];
1190
+ put?: never;
1191
+ post?: never;
1192
+ delete?: never;
1193
+ options?: never;
1194
+ head?: never;
1195
+ patch?: never;
1196
+ trace?: never;
1197
+ };
1198
+ "/api/v1/organizations/{id}/nodes/{nodeId}/members": {
1199
+ parameters: {
1200
+ query?: never;
1201
+ header?: never;
1202
+ path?: never;
1203
+ cookie?: never;
1204
+ };
1205
+ /**
1206
+ * List the organization's members, for granting a role at a node
1207
+ * @description The organization's members as candidates for a role at the node: each row names the identity only. Paginated; `q` searches name and email. Requires the same as the grantable-roles read at the node, so an administrator of one office may choose from the whole organization's roster without reading what anyone else holds.
1208
+ */
1209
+ get: operations["ApiOrganizationAccessController_listMembersAt"];
1210
+ put?: never;
1211
+ post?: never;
1212
+ delete?: never;
1213
+ options?: never;
1214
+ head?: never;
1215
+ patch?: never;
1216
+ trace?: never;
1217
+ };
1218
+ "/api/v1/organizations/{id}/assignments": {
1219
+ parameters: {
1220
+ query?: never;
1221
+ header?: never;
1222
+ path?: never;
1223
+ cookie?: never;
1224
+ };
1225
+ get?: never;
1226
+ put?: never;
1227
+ /**
1228
+ * Grant a role at a node beneath the organization
1229
+ * @description Grants `role_id` to `identity_id` at `node_id`, the organization node or one beneath it. The identity must be a member of the organization (`409 organization.membership_required` otherwise). Requires `rbac.manage_assignments` at the node, `canopy:organization.manage` at the organization, or `canopy:access.manage` at the node or above it, within the grant ceiling. Emits `assignment.created`.
1230
+ */
1231
+ post: operations["ApiOrganizationAccessController_createAssignment"];
1232
+ delete?: never;
1233
+ options?: never;
1234
+ head?: never;
1235
+ patch?: never;
1236
+ trace?: never;
1237
+ };
1238
+ "/api/v1/organizations/{id}/assignments/{assignmentId}": {
1239
+ parameters: {
1240
+ query?: never;
1241
+ header?: never;
1242
+ path?: never;
1243
+ cookie?: never;
1244
+ };
1245
+ get?: never;
1246
+ put?: never;
1247
+ post?: never;
1248
+ /**
1249
+ * Take a grant in the organization away
1250
+ * @description Removes an assignment at the organization node or beneath it; the membership stays. Never bounded by the grant ceiling, but the last administrator's role at the organization node cannot be removed (`409 organization.last_admin`). Requires the same as creating one.
1251
+ */
1252
+ delete: operations["ApiOrganizationAccessController_removeAssignment"];
1253
+ options?: never;
1254
+ head?: never;
1255
+ /**
1256
+ * Change a grant in the organization
1257
+ * @description Changes the role or the window of an assignment at the organization node or beneath it. A new role meets the grant ceiling; dates alone do not. The last administrator's role at the organization node cannot be changed away (`409 organization.last_admin`). Requires the same as creating one.
1258
+ */
1259
+ patch: operations["ApiOrganizationAccessController_updateAssignment"];
1260
+ trace?: never;
1261
+ };
1078
1262
  "/api/v1/organizations": {
1079
1263
  parameters: {
1080
1264
  query?: never;
@@ -1332,13 +1516,13 @@ interface paths {
1332
1516
  };
1333
1517
  /**
1334
1518
  * List an organization's members
1335
- * @description Lists the organization's members: each row is the member's identity, their single role in this organization, effective dates, when they joined, and `node_assignments`, the grants the member also holds at nodes beneath the organization (empty in a flat Environment). Paginated; `q` searches name and email. Requires the `rbac.view_assignments` permission at the organization.
1519
+ * @description Lists the organization's members: each row is the membership (its `status`, `source` and `joined_at`), the member's identity, and `roles`, every role assignment the member holds in the organization, at its node and beneath, with the node and the effective window. Active members by default; `status=deactivated` lists those who left and `status=all` both. Paginated; `q` searches name and email, `role_id` keeps members holding that role anywhere in the organization. Requires the `rbac.view_assignments` permission at the organization.
1336
1520
  */
1337
1521
  get: operations["ApiOrganizationsController_listMembers"];
1338
1522
  put?: never;
1339
1523
  /**
1340
1524
  * 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`. 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.
1525
+ * @description Adds a member. Membership is admission, not authority: with `role_id` the member also holds that role at the organization node from the start; without it they belong and hold nothing until a role is assigned. The identity must already hold an active membership in this Environment (invite by email instead for someone who does not). An identity that is already a member returns `409`; roles are added through the assignment routes. 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
1526
  */
1343
1527
  post: operations["ApiOrganizationsController_addMember"];
1344
1528
  delete?: never;
@@ -1359,16 +1543,12 @@ interface paths {
1359
1543
  post?: never;
1360
1544
  /**
1361
1545
  * Remove a member from an organization
1362
- * @description Removes the member from this organization, revoking their role here and nothing else — the identity and its memberships in other organizations are untouched. Returns `404` when the identity is not a member. Responds `204 No Content`, requires the `rbac.manage_assignments` permission at the organization, and emits `organization.member.removed`.
1546
+ * @description Removes the member from this organization: the membership is deactivated and every role assignment they hold at the organization's nodes goes with it, and nothing else; the identity and its memberships in other organizations are untouched. Returns `404` when the identity is not an active member and `409` when they are the last administrator. Responds `204 No Content`, requires the `rbac.manage_assignments` permission at the organization, and emits `organization.member.removed`.
1363
1547
  */
1364
1548
  delete: operations["ApiOrganizationsController_removeMember"];
1365
1549
  options?: never;
1366
1550
  head?: never;
1367
- /**
1368
- * Change a member's role
1369
- * @description Replaces the member's role in this organization with `role_id`. A member holds exactly one role per organization, so this updates the existing membership in place; changing to the role already held is a no-op. Returns `404` when the identity is not a member. Requires the `rbac.manage_assignments` permission at the organization and emits `organization.member.role_changed`.
1370
- */
1371
- patch: operations["ApiOrganizationsController_changeMemberRole"];
1551
+ patch?: never;
1372
1552
  trace?: never;
1373
1553
  };
1374
1554
  "/api/v1/organizations/{id}/members/{identityId}/mfa/reset": {
@@ -1424,7 +1604,7 @@ interface paths {
1424
1604
  };
1425
1605
  /**
1426
1606
  * List the roles an organization may assign
1427
- * @description The active, assignable roles of the organization's Environment, for choosing a member's role or an invitation's. System roles are left out, since they cannot be assigned. Requires `hierarchy.view` or `canopy:organization.manage` at the organization. The response is an unpaginated `{ items }` array.
1607
+ * @description The active, assignable roles of the organization's Environment, for choosing a member's role or an invitation's, each with `grantable`: whether the caller may grant it at the organization node under the grant ceiling (always true for the developer's key). System roles are left out, since they cannot be assigned. Requires `hierarchy.view`, `canopy:organization.manage` at the organization, or `canopy:access.manage` at the organization node. The response is an unpaginated `{ items }` array.
1428
1608
  */
1429
1609
  get: operations["ApiOrganizationsController_listRoles"];
1430
1610
  put?: never;
@@ -2484,6 +2664,7 @@ interface components {
2484
2664
  effective_node_id?: string | null;
2485
2665
  /** @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
2666
  granting_roles: string[];
2667
+ /** @description Why the check was refused: `NO_ROLE_ASSIGNMENT`, `PERMISSION_NOT_GRANTED`, `NODE_SCOPE_VIOLATION`, `ROLE_EXPIRED`, `IDENTITY_INACTIVE`, `IDENTITY_NOT_ENV_MEMBER`, or `ORGANIZATION_MEMBERSHIP_INACTIVE` (assignments sit on the lineage inside an organization the identity's membership in is deactivated, so none count). Null on an allow. */
2487
2668
  denial_reason?: string | null;
2488
2669
  };
2489
2670
  EvaluatePermissionDto: {
@@ -2518,7 +2699,7 @@ interface components {
2518
2699
  assignment_id: string;
2519
2700
  role_id: string;
2520
2701
  role_name: string;
2521
- /** @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. */
2702
+ /** @description Whether the assignment counts right now: within its effective_from/effective_to window, its role active, and, inside an organization, the holder's membership there active. An assignment that fails any of these is listed but grants nothing. */
2522
2703
  active: boolean;
2523
2704
  effective_from?: string | null;
2524
2705
  effective_to?: string | null;
@@ -2592,6 +2773,8 @@ interface components {
2592
2773
  effective_from: string | null;
2593
2774
  /** @description When this assignment expires; null means it never does */
2594
2775
  effective_to: string | null;
2776
+ /** @description Optimistic-lock version; send it back as `If-Match` */
2777
+ version: number;
2595
2778
  };
2596
2779
  IdentityRowDto: {
2597
2780
  id: string;
@@ -2738,6 +2921,20 @@ interface components {
2738
2921
  created_at: string;
2739
2922
  /** Format: date-time */
2740
2923
  updated_at: string;
2924
+ /** @description Optimistic-lock version; send it back as `If-Match` */
2925
+ version: number;
2926
+ };
2927
+ IdentityAccessibleNodesResponseDto: {
2928
+ /** @example reports.view */
2929
+ permission: string;
2930
+ /** @description True when a root is the Environment's own root, so every node qualifies and a list needs no filter. `nodes` is null then. */
2931
+ env_wide: boolean;
2932
+ /** @description The nodes the permission is granted at, in effect now, that no other such node already covers. Each reaches everything beneath it. */
2933
+ roots: string[];
2934
+ /** @description Every node beneath the roots, the roots included, for an `IN (...)` filter. Null when `env_wide`, or when there are more than `max_nodes` (then `complete` is false and the caller filters by `roots` instead). */
2935
+ nodes: string[] | null;
2936
+ /** @description False when the set beneath the roots was larger than `max_nodes` and was not sent. */
2937
+ complete: boolean;
2741
2938
  };
2742
2939
  IdentityGrantResponseDto: {
2743
2940
  /** @example reports.view */
@@ -2747,6 +2944,16 @@ interface components {
2747
2944
  * @description The hierarchy node the permission was granted at. Not expanded through descendants.
2748
2945
  */
2749
2946
  node_id: string;
2947
+ /**
2948
+ * Format: date-time
2949
+ * @description When the assignment behind this root begins, or null for no start. Present only with `include=windows`.
2950
+ */
2951
+ effective_from?: string | null;
2952
+ /**
2953
+ * Format: date-time
2954
+ * @description When the assignment behind this root ends, or null for no end. Present only with `include=windows`.
2955
+ */
2956
+ effective_to?: string | null;
2750
2957
  };
2751
2958
  IdentityInviteResponseDto: {
2752
2959
  id: string;
@@ -2957,6 +3164,8 @@ interface components {
2957
3164
  status: "active" | "scheduled" | "expired";
2958
3165
  /** Format: date-time */
2959
3166
  created_at: string;
3167
+ /** @description Optimistic-lock version; send it back as `If-Match` */
3168
+ version: number;
2960
3169
  };
2961
3170
  IdentityAssignmentRowDto: {
2962
3171
  identity: components["schemas"]["AssignmentIdentityDto"];
@@ -2981,6 +3190,65 @@ interface components {
2981
3190
  distinct_role_count: number;
2982
3191
  recent_identities: components["schemas"]["RecentIdentityDto"][];
2983
3192
  };
3193
+ OrganizationAuthorityRootDto: {
3194
+ node_id: string;
3195
+ name: string;
3196
+ /** @description The node's type, as the schema names it */
3197
+ node_type: string;
3198
+ /** @description The names from the organization node down to this node's parent, so the node can be named in context; empty for the organization node itself */
3199
+ path: string[];
3200
+ };
3201
+ OrganizationMeResponseDto: {
3202
+ /** @description Holds `canopy:organization.manage` at the organization node, or is the developer's key */
3203
+ administers_organization: boolean;
3204
+ /** @description The topmost nodes where `canopy:access.manage` is held inside the organization; the organization node when `administers_organization` */
3205
+ access_roots: components["schemas"]["OrganizationAuthorityRootDto"][];
3206
+ /** @description The same for `canopy:structure.manage`, a key no role carries yet; always empty */
3207
+ structure_roots: components["schemas"]["OrganizationAuthorityRootDto"][];
3208
+ /** @description The same for `canopy:roles.manage`, a key no role carries yet; always empty */
3209
+ roles_roots: components["schemas"]["OrganizationAuthorityRootDto"][];
3210
+ /** @description Whether the Environment's schema allows nodes beneath an organization; false in a flat Environment, where the organization is its only node */
3211
+ has_hierarchy: boolean;
3212
+ };
3213
+ RoleResponseDto: {
3214
+ id: string;
3215
+ application_id: string;
3216
+ name: string;
3217
+ description?: string | null;
3218
+ is_system_role: boolean;
3219
+ system_key?: string | null;
3220
+ is_active: boolean;
3221
+ /** Format: date-time */
3222
+ created_at: string;
3223
+ /** Format: date-time */
3224
+ updated_at: string;
3225
+ /** @description Optimistic-lock version. Send back as the `If-Match` header when updating to detect concurrent edits. */
3226
+ version: number;
3227
+ /** @description Number of permissions currently assigned to this role. Populated on list responses; omitted on single-role responses where the join isn't computed. */
3228
+ permission_count?: number;
3229
+ /** @description Number of distinct identities assigned this role. Populated on list responses; omitted on single-role responses where the join isn't computed. */
3230
+ member_count?: number;
3231
+ };
3232
+ OrganizationMemberCandidateResponseDto: {
3233
+ identity: components["schemas"]["AssignmentIdentityDto"];
3234
+ };
3235
+ CreateOrganizationAssignmentDto: {
3236
+ /** @description A member of the organization */
3237
+ identity_id: string;
3238
+ /** @description The organization node, or a node beneath it; the identity must be an active member of the organization */
3239
+ node_id: string;
3240
+ /** @description An active, assignable role of the Environment */
3241
+ role_id: string;
3242
+ /** @description When the grant starts (ISO 8601); now when omitted */
3243
+ effective_from?: Record<string, unknown>;
3244
+ /** @description When the grant ends (ISO 8601); never when omitted */
3245
+ effective_to?: Record<string, unknown>;
3246
+ };
3247
+ UpdateAssignmentDto: {
3248
+ role_id: string;
3249
+ effective_from?: string | null;
3250
+ effective_to?: string | null;
3251
+ };
2984
3252
  OrganizationResponseDto: {
2985
3253
  id: string;
2986
3254
  name: string;
@@ -2990,7 +3258,7 @@ interface components {
2990
3258
  metadata: Record<string, unknown>;
2991
3259
  /** @description Your own id for this organization, unique per Environment. */
2992
3260
  external_id?: string | null;
2993
- /** @description Members (one role each) in this organization. */
3261
+ /** @description Active members of this organization, whatever roles they hold. */
2994
3262
  member_count: number;
2995
3263
  /** @description Unexpired, unaccepted, unrevoked invitations. */
2996
3264
  pending_invite_count: number;
@@ -3181,38 +3449,52 @@ interface components {
3181
3449
  name: string;
3182
3450
  node_type: string;
3183
3451
  };
3184
- OrganizationMemberNodeAssignmentDto: {
3452
+ OrganizationMemberAssignmentDto: {
3185
3453
  /** @description The assignment id. */
3186
3454
  id: string;
3187
- application_node: components["schemas"]["OrganizationMemberNodeDto"];
3188
- role: components["schemas"]["OrganizationMemberRoleDto"];
3189
- };
3190
- OrganizationMemberResponseDto: {
3191
- /** @description The membership (role assignment) id. */
3192
- id: string;
3193
- identity: components["schemas"]["OrganizationMemberIdentityDto"];
3194
3455
  role: components["schemas"]["OrganizationMemberRoleDto"];
3456
+ node: components["schemas"]["OrganizationMemberNodeDto"];
3195
3457
  /** Format: date-time */
3196
3458
  effective_from?: string | null;
3197
3459
  /** Format: date-time */
3198
3460
  effective_to?: string | null;
3461
+ /** @description The assignment's version, for `If-Match` on a change. */
3462
+ version: number;
3463
+ };
3464
+ OrganizationMemberResponseDto: {
3465
+ /** @description The membership id. */
3466
+ id: string;
3467
+ identity: components["schemas"]["OrganizationMemberIdentityDto"];
3468
+ /**
3469
+ * @description `active` while the identity belongs; `deactivated` once removed, kept for the organization's history.
3470
+ * @enum {string}
3471
+ */
3472
+ status: "active" | "deactivated";
3473
+ /**
3474
+ * @description How the membership began: added by an administrator, an accepted invitation, single sign-on, directory sync, or the organization's own creation on sign-up.
3475
+ * @enum {string}
3476
+ */
3477
+ source: "added" | "invitation" | "sso" | "directory_sync" | "signup";
3199
3478
  /**
3200
3479
  * Format: date-time
3201
- * @description When the membership was created.
3480
+ * @description When the current membership began.
3202
3481
  */
3203
- created_at: string;
3204
- /** @description Assignments the member also holds at nodes beneath the organization. Empty in a flat Environment. */
3205
- node_assignments: components["schemas"]["OrganizationMemberNodeAssignmentDto"][];
3482
+ joined_at: string;
3483
+ /**
3484
+ * Format: date-time
3485
+ * @description When the member was removed; null while active.
3486
+ */
3487
+ deactivated_at?: string | null;
3488
+ /** @description Every role assignment the member holds in the organization, the organization node first, then beneath it. Empty for a member who holds none. */
3489
+ roles: components["schemas"]["OrganizationMemberAssignmentDto"][];
3490
+ /** @description The membership's version. */
3491
+ version: number;
3206
3492
  };
3207
3493
  AddOrganizationMemberDto: {
3208
3494
  /** @description Identity to add. Must already hold an active membership in this Environment; invite by email instead for someone who does not. */
3209
3495
  identity_id: string;
3210
- /** @description The single role the member holds in this organization, from the Environment's roles. */
3211
- role_id: string;
3212
- };
3213
- ChangeOrganizationMemberRoleDto: {
3214
- /** @description The replacement role. A member holds exactly one role per organization, so this updates the existing membership in place. */
3215
- role_id: string;
3496
+ /** @description A role to hold at the organization node from the start, from the Environment's roles. Left out, the member belongs and holds nothing until a role is assigned. */
3497
+ role_id?: string;
3216
3498
  };
3217
3499
  CreateOrganizationInviteDto: {
3218
3500
  /** @description Email to invite. Works for people with no identity in this Environment — one is created when they accept. */
@@ -3227,7 +3509,7 @@ interface components {
3227
3509
  */
3228
3510
  send_email: boolean;
3229
3511
  };
3230
- RoleResponseDto: {
3512
+ OrganizationRoleResponseDto: {
3231
3513
  id: string;
3232
3514
  application_id: string;
3233
3515
  name: string;
@@ -3245,6 +3527,8 @@ interface components {
3245
3527
  permission_count?: number;
3246
3528
  /** @description Number of distinct identities assigned this role. Populated on list responses; omitted on single-role responses where the join isn't computed. */
3247
3529
  member_count?: number;
3530
+ /** @description Whether the caller may grant this role at the organization node under the grant ceiling: for an identity, it holds every permission the role carries there; always true for the developer's key and Console users */
3531
+ grantable: boolean;
3248
3532
  };
3249
3533
  SsoConnectionTestSummaryDto: {
3250
3534
  test_id: string;
@@ -3554,11 +3838,6 @@ interface components {
3554
3838
  effective_from?: string;
3555
3839
  effective_to?: string;
3556
3840
  };
3557
- UpdateAssignmentDto: {
3558
- role_id: string;
3559
- effective_from?: string | null;
3560
- effective_to?: string | null;
3561
- };
3562
3841
  BulkRemoveAssignmentsDto: {
3563
3842
  assignment_ids: string[];
3564
3843
  };
@@ -4999,16 +5278,21 @@ interface components {
4999
5278
  * @description The identity that joined.
5000
5279
  */
5001
5280
  identity_id: string;
5281
+ /** @description Your own identifier for the organization, when you set one. */
5282
+ external_id?: string | null;
5002
5283
  /**
5003
5284
  * Format: uuid
5004
- * @description The role it holds in the organization.
5285
+ * @description The membership record.
5005
5286
  */
5006
- role_id: string;
5007
- /** @description Your own identifier for the organization, when you set one. */
5008
- external_id?: string | null;
5287
+ membership_id?: string;
5288
+ /**
5289
+ * Format: uuid
5290
+ * @description The role given at the organization node on joining, when one was.
5291
+ */
5292
+ role_id?: string;
5009
5293
  /**
5010
5294
  * Format: uuid
5011
- * @description The role assignment that is the membership.
5295
+ * @description That role's assignment, when a role was given.
5012
5296
  */
5013
5297
  assignment_id?: string;
5014
5298
  /**
@@ -5030,7 +5314,7 @@ interface components {
5030
5314
  * @description How the member joined, when it was not added directly.
5031
5315
  * @enum {string}
5032
5316
  */
5033
- source?: "sso_jit" | "invite" | "scim";
5317
+ source?: "sso_jit" | "invite" | "scim" | "self_signup";
5034
5318
  };
5035
5319
  };
5036
5320
  };
@@ -5087,13 +5371,13 @@ interface components {
5087
5371
  * @description The identity removed.
5088
5372
  */
5089
5373
  identity_id: string;
5374
+ /** @description Role assignments it held at the organization's nodes, removed with the membership. */
5375
+ assignments_removed: number;
5090
5376
  /**
5091
5377
  * Format: uuid
5092
- * @description The role it held.
5378
+ * @description The membership record, now deactivated.
5093
5379
  */
5094
- role_id: string;
5095
- /** @description Grants it held beneath the organization, removed with the membership. */
5096
- scoped_assignments_removed: number;
5380
+ membership_id?: string;
5097
5381
  /**
5098
5382
  * @description Set when directory sync made the change rather than somebody directly.
5099
5383
  * @enum {string}
@@ -5541,8 +5825,7 @@ interface operations {
5541
5825
  ApiPermissionsController_deletePermission: {
5542
5826
  parameters: {
5543
5827
  query?: never;
5544
- header: {
5545
- "if-match": string;
5828
+ header?: {
5546
5829
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
5547
5830
  "If-Match"?: string;
5548
5831
  };
@@ -5670,8 +5953,7 @@ interface operations {
5670
5953
  ApiPermissionsController_updatePermission: {
5671
5954
  parameters: {
5672
5955
  query?: never;
5673
- header: {
5674
- "if-match": string;
5956
+ header?: {
5675
5957
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
5676
5958
  "If-Match"?: string;
5677
5959
  };
@@ -8358,7 +8640,10 @@ interface operations {
8358
8640
  };
8359
8641
  ApiIdentitiesController_getIdentityPermissions: {
8360
8642
  parameters: {
8361
- query?: never;
8643
+ query?: {
8644
+ /** @description Answer at this node: the permissions granted by assignments on its lineage. Omit for the Application-wide answer. */
8645
+ node_id?: string;
8646
+ };
8362
8647
  header?: never;
8363
8648
  path: {
8364
8649
  id: string;
@@ -8464,13 +8749,13 @@ interface operations {
8464
8749
  };
8465
8750
  };
8466
8751
  };
8467
- ApiIdentitiesController_getIdentityGrants: {
8752
+ ApiIdentitiesController_getIdentityAccessibleNodes: {
8468
8753
  parameters: {
8469
- query?: {
8470
- /** @description Page number (1-based) */
8471
- page?: number;
8472
- /** @description Items per page (1-100, default 20) */
8473
- take?: number;
8754
+ query: {
8755
+ /** @description The permission to answer for, by key. */
8756
+ permission: string;
8757
+ /** @description The largest `nodes` set to return. Past it, `nodes` is null and `complete` false. */
8758
+ max_nodes?: number;
8474
8759
  };
8475
8760
  header?: never;
8476
8761
  path: {
@@ -8480,15 +8765,130 @@ interface operations {
8480
8765
  };
8481
8766
  requestBody?: never;
8482
8767
  responses: {
8483
- /** @description One page of grant roots, one row per permission and node, ordered by permission then node */
8768
+ /** @description The minimal grant roots for the permission, and the nodes beneath them up to the cap */
8484
8769
  200: {
8485
8770
  headers: {
8486
8771
  [name: string]: unknown;
8487
8772
  };
8488
8773
  content: {
8489
8774
  "application/json": {
8490
- /** @description The version of the authorization model these rows describe. A client that evaluates from them refuses a version it does not know rather than guessing. */
8491
- model_version: number;
8775
+ data: components["schemas"]["IdentityAccessibleNodesResponseDto"];
8776
+ };
8777
+ };
8778
+ };
8779
+ /** @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 */
8780
+ 400: {
8781
+ headers: {
8782
+ [name: string]: unknown;
8783
+ };
8784
+ content: {
8785
+ /**
8786
+ * @example {
8787
+ * "error": {
8788
+ * "statusCode": 400,
8789
+ * "code": null,
8790
+ * "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",
8791
+ * "timestamp": "2026-04-20T12:00:00.000Z",
8792
+ * "path": "/api/v1/identities/{id}/accessible-nodes",
8793
+ * "method": "GET"
8794
+ * }
8795
+ * }
8796
+ */
8797
+ "application/json": components["schemas"]["ErrorResponseDto"];
8798
+ };
8799
+ };
8800
+ /** @description Invalid or expired token */
8801
+ 401: {
8802
+ headers: {
8803
+ [name: string]: unknown;
8804
+ };
8805
+ content: {
8806
+ /**
8807
+ * @example {
8808
+ * "error": {
8809
+ * "statusCode": 401,
8810
+ * "code": null,
8811
+ * "message": "Invalid or expired token",
8812
+ * "timestamp": "2026-04-20T12:00:00.000Z",
8813
+ * "path": "/api/v1/identities",
8814
+ * "method": "GET"
8815
+ * }
8816
+ * }
8817
+ */
8818
+ "application/json": components["schemas"]["ErrorResponseDto"];
8819
+ };
8820
+ };
8821
+ /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
8822
+ 403: {
8823
+ headers: {
8824
+ [name: string]: unknown;
8825
+ };
8826
+ content: {
8827
+ /**
8828
+ * @example {
8829
+ * "error": {
8830
+ * "statusCode": 403,
8831
+ * "code": null,
8832
+ * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
8833
+ * "timestamp": "2026-04-20T12:00:00.000Z",
8834
+ * "path": "/api/v1/identities",
8835
+ * "method": "GET"
8836
+ * }
8837
+ * }
8838
+ */
8839
+ "application/json": components["schemas"]["ErrorResponseDto"];
8840
+ };
8841
+ };
8842
+ /** @description No identity with that id has a membership in this Environment */
8843
+ 404: {
8844
+ headers: {
8845
+ [name: string]: unknown;
8846
+ };
8847
+ content: {
8848
+ /**
8849
+ * @example {
8850
+ * "error": {
8851
+ * "statusCode": 404,
8852
+ * "code": null,
8853
+ * "message": "No identity with that id has a membership in this Environment",
8854
+ * "timestamp": "2026-04-20T12:00:00.000Z",
8855
+ * "path": "/api/v1/identities/{id}/accessible-nodes",
8856
+ * "method": "GET"
8857
+ * }
8858
+ * }
8859
+ */
8860
+ "application/json": components["schemas"]["ErrorResponseDto"];
8861
+ };
8862
+ };
8863
+ };
8864
+ };
8865
+ ApiIdentitiesController_getIdentityGrants: {
8866
+ parameters: {
8867
+ query?: {
8868
+ /** @description Page number (1-based) */
8869
+ page?: number;
8870
+ /** @description Items per page (1-100, default 20) */
8871
+ take?: number;
8872
+ /** @description `windows` adds `effective_from` and `effective_to` to every row and includes assignments outside their window, so the caller applies the window itself. */
8873
+ include?: "windows";
8874
+ };
8875
+ header?: never;
8876
+ path: {
8877
+ id: string;
8878
+ };
8879
+ cookie?: never;
8880
+ };
8881
+ requestBody?: never;
8882
+ responses: {
8883
+ /** @description One page of grant roots, one row per permission and node, ordered by permission then node */
8884
+ 200: {
8885
+ headers: {
8886
+ [name: string]: unknown;
8887
+ };
8888
+ content: {
8889
+ "application/json": {
8890
+ /** @description The version of the authorization model these rows describe. A client that evaluates from them refuses a version it does not know rather than guessing. */
8891
+ model_version: number;
8492
8892
  items: components["schemas"]["IdentityGrantResponseDto"][];
8493
8893
  pagination: components["schemas"]["PageMetaDto"];
8494
8894
  };
@@ -9683,8 +10083,7 @@ interface operations {
9683
10083
  ApiNodesController_deleteNode: {
9684
10084
  parameters: {
9685
10085
  query?: never;
9686
- header: {
9687
- "if-match": string;
10086
+ header?: {
9688
10087
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
9689
10088
  "If-Match"?: string;
9690
10089
  };
@@ -9812,8 +10211,7 @@ interface operations {
9812
10211
  ApiNodesController_updateNode: {
9813
10212
  parameters: {
9814
10213
  query?: never;
9815
- header: {
9816
- "if-match": string;
10214
+ header?: {
9817
10215
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
9818
10216
  "If-Match"?: string;
9819
10217
  };
@@ -10234,8 +10632,7 @@ interface operations {
10234
10632
  ApiNodesController_moveNode: {
10235
10633
  parameters: {
10236
10634
  query?: never;
10237
- header: {
10238
- "if-match": string;
10635
+ header?: {
10239
10636
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
10240
10637
  "If-Match"?: string;
10241
10638
  };
@@ -10539,8 +10936,1100 @@ interface operations {
10539
10936
  "application/json": components["schemas"]["ErrorResponseDto"];
10540
10937
  };
10541
10938
  };
10542
- /** @description Invalid or expired token */
10543
- 401: {
10939
+ /** @description Invalid or expired token */
10940
+ 401: {
10941
+ headers: {
10942
+ [name: string]: unknown;
10943
+ };
10944
+ content: {
10945
+ /**
10946
+ * @example {
10947
+ * "error": {
10948
+ * "statusCode": 401,
10949
+ * "code": null,
10950
+ * "message": "Invalid or expired token",
10951
+ * "timestamp": "2026-04-20T12:00:00.000Z",
10952
+ * "path": "/api/v1/nodes",
10953
+ * "method": "GET"
10954
+ * }
10955
+ * }
10956
+ */
10957
+ "application/json": components["schemas"]["ErrorResponseDto"];
10958
+ };
10959
+ };
10960
+ /** @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 */
10961
+ 403: {
10962
+ headers: {
10963
+ [name: string]: unknown;
10964
+ };
10965
+ content: {
10966
+ /**
10967
+ * @example {
10968
+ * "error": {
10969
+ * "statusCode": 403,
10970
+ * "code": null,
10971
+ * "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",
10972
+ * "timestamp": "2026-04-20T12:00:00.000Z",
10973
+ * "path": "/api/v1/nodes",
10974
+ * "method": "GET"
10975
+ * }
10976
+ * }
10977
+ */
10978
+ "application/json": components["schemas"]["ErrorResponseDto"];
10979
+ };
10980
+ };
10981
+ /** @description Node not found */
10982
+ 404: {
10983
+ headers: {
10984
+ [name: string]: unknown;
10985
+ };
10986
+ content: {
10987
+ /**
10988
+ * @example {
10989
+ * "error": {
10990
+ * "statusCode": 404,
10991
+ * "code": null,
10992
+ * "message": "Node not found",
10993
+ * "timestamp": "2026-04-20T12:00:00.000Z",
10994
+ * "path": "/api/v1/nodes/{id}/identities/summary",
10995
+ * "method": "GET"
10996
+ * }
10997
+ * }
10998
+ */
10999
+ "application/json": components["schemas"]["ErrorResponseDto"];
11000
+ };
11001
+ };
11002
+ };
11003
+ };
11004
+ ApiOrganizationAccessController_me: {
11005
+ parameters: {
11006
+ query?: never;
11007
+ header?: never;
11008
+ path: {
11009
+ id: string;
11010
+ };
11011
+ cookie?: never;
11012
+ };
11013
+ requestBody?: never;
11014
+ responses: {
11015
+ /** @description The caller's authority in the organization */
11016
+ 200: {
11017
+ headers: {
11018
+ [name: string]: unknown;
11019
+ };
11020
+ content: {
11021
+ "application/json": {
11022
+ data: components["schemas"]["OrganizationMeResponseDto"];
11023
+ };
11024
+ };
11025
+ };
11026
+ /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
11027
+ 400: {
11028
+ headers: {
11029
+ [name: string]: unknown;
11030
+ };
11031
+ content: {
11032
+ /**
11033
+ * @example {
11034
+ * "error": {
11035
+ * "statusCode": 400,
11036
+ * "code": null,
11037
+ * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
11038
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11039
+ * "path": "/api/v1/organizations/{id}/me",
11040
+ * "method": "GET"
11041
+ * }
11042
+ * }
11043
+ */
11044
+ "application/json": components["schemas"]["ErrorResponseDto"];
11045
+ };
11046
+ };
11047
+ /** @description Invalid or expired token */
11048
+ 401: {
11049
+ headers: {
11050
+ [name: string]: unknown;
11051
+ };
11052
+ content: {
11053
+ /**
11054
+ * @example {
11055
+ * "error": {
11056
+ * "statusCode": 401,
11057
+ * "code": null,
11058
+ * "message": "Invalid or expired token",
11059
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11060
+ * "path": "/api/v1/organizations/{id}/me",
11061
+ * "method": "GET"
11062
+ * }
11063
+ * }
11064
+ */
11065
+ "application/json": components["schemas"]["ErrorResponseDto"];
11066
+ };
11067
+ };
11068
+ /** @description The caller holds no delegated key inside the organization and no developer key over it, or the token is not an admin, API key or identity token */
11069
+ 403: {
11070
+ headers: {
11071
+ [name: string]: unknown;
11072
+ };
11073
+ content: {
11074
+ /**
11075
+ * @example {
11076
+ * "error": {
11077
+ * "statusCode": 403,
11078
+ * "code": null,
11079
+ * "message": "The caller holds no delegated key inside the organization and no developer key over it, or the token is not an admin, API key or identity token",
11080
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11081
+ * "path": "/api/v1/organizations/{id}/me",
11082
+ * "method": "GET"
11083
+ * }
11084
+ * }
11085
+ */
11086
+ "application/json": components["schemas"]["ErrorResponseDto"];
11087
+ };
11088
+ };
11089
+ /** @description Organization not found */
11090
+ 404: {
11091
+ headers: {
11092
+ [name: string]: unknown;
11093
+ };
11094
+ content: {
11095
+ /**
11096
+ * @example {
11097
+ * "error": {
11098
+ * "statusCode": 404,
11099
+ * "code": null,
11100
+ * "message": "Organization not found",
11101
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11102
+ * "path": "/api/v1/organizations/{id}/me",
11103
+ * "method": "GET"
11104
+ * }
11105
+ * }
11106
+ */
11107
+ "application/json": components["schemas"]["ErrorResponseDto"];
11108
+ };
11109
+ };
11110
+ };
11111
+ };
11112
+ ApiOrganizationAccessController_tree: {
11113
+ parameters: {
11114
+ query?: {
11115
+ /** @description Page number (1-based) */
11116
+ page?: number;
11117
+ /** @description Items per page (1-100, default 20) */
11118
+ take?: number;
11119
+ /** @description Search node names and slugs */
11120
+ q?: string;
11121
+ /** @description Sort column. Defaults to `created`, oldest first. */
11122
+ sort_by?: "name" | "created";
11123
+ /** @description Sort direction */
11124
+ order?: "asc" | "desc";
11125
+ };
11126
+ header?: never;
11127
+ path: {
11128
+ id: string;
11129
+ };
11130
+ cookie?: never;
11131
+ };
11132
+ requestBody?: never;
11133
+ responses: {
11134
+ /** @description Nodes returned */
11135
+ 200: {
11136
+ headers: {
11137
+ [name: string]: unknown;
11138
+ };
11139
+ content: {
11140
+ "application/json": {
11141
+ items: components["schemas"]["ScopedNodeResponseDto"][];
11142
+ pagination: components["schemas"]["PageMetaDto"];
11143
+ };
11144
+ };
11145
+ };
11146
+ /** @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 */
11147
+ 400: {
11148
+ headers: {
11149
+ [name: string]: unknown;
11150
+ };
11151
+ content: {
11152
+ /**
11153
+ * @example {
11154
+ * "error": {
11155
+ * "statusCode": 400,
11156
+ * "code": null,
11157
+ * "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",
11158
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11159
+ * "path": "/api/v1/organizations/{id}/tree",
11160
+ * "method": "GET"
11161
+ * }
11162
+ * }
11163
+ */
11164
+ "application/json": components["schemas"]["ErrorResponseDto"];
11165
+ };
11166
+ };
11167
+ /** @description Invalid or expired token */
11168
+ 401: {
11169
+ headers: {
11170
+ [name: string]: unknown;
11171
+ };
11172
+ content: {
11173
+ /**
11174
+ * @example {
11175
+ * "error": {
11176
+ * "statusCode": 401,
11177
+ * "code": null,
11178
+ * "message": "Invalid or expired token",
11179
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11180
+ * "path": "/api/v1/organizations/{id}/me",
11181
+ * "method": "GET"
11182
+ * }
11183
+ * }
11184
+ */
11185
+ "application/json": components["schemas"]["ErrorResponseDto"];
11186
+ };
11187
+ };
11188
+ /** @description The caller holds no delegated key inside the organization and no developer key over it, or the token is not an admin, API key or identity token */
11189
+ 403: {
11190
+ headers: {
11191
+ [name: string]: unknown;
11192
+ };
11193
+ content: {
11194
+ /**
11195
+ * @example {
11196
+ * "error": {
11197
+ * "statusCode": 403,
11198
+ * "code": null,
11199
+ * "message": "The caller holds no delegated key inside the organization and no developer key over it, or the token is not an admin, API key or identity token",
11200
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11201
+ * "path": "/api/v1/organizations/{id}/tree",
11202
+ * "method": "GET"
11203
+ * }
11204
+ * }
11205
+ */
11206
+ "application/json": components["schemas"]["ErrorResponseDto"];
11207
+ };
11208
+ };
11209
+ /** @description Organization not found */
11210
+ 404: {
11211
+ headers: {
11212
+ [name: string]: unknown;
11213
+ };
11214
+ content: {
11215
+ /**
11216
+ * @example {
11217
+ * "error": {
11218
+ * "statusCode": 404,
11219
+ * "code": null,
11220
+ * "message": "Organization not found",
11221
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11222
+ * "path": "/api/v1/organizations/{id}/tree",
11223
+ * "method": "GET"
11224
+ * }
11225
+ * }
11226
+ */
11227
+ "application/json": components["schemas"]["ErrorResponseDto"];
11228
+ };
11229
+ };
11230
+ };
11231
+ };
11232
+ ApiOrganizationAccessController_listAccess: {
11233
+ parameters: {
11234
+ query?: {
11235
+ /** @description Page number (1-based) */
11236
+ page?: number;
11237
+ /** @description Items per page (1-100, default 20) */
11238
+ take?: number;
11239
+ /** @description Search term */
11240
+ q?: string;
11241
+ /** @description Sort field */
11242
+ sort_by?: "name" | "role" | "access_type" | "created_at";
11243
+ /** @description Sort order */
11244
+ order?: "asc" | "desc";
11245
+ /** @description Filter by role ID */
11246
+ role_id?: string;
11247
+ /** @description Filter by access type */
11248
+ access_type?: "direct" | "inherited";
11249
+ /** @description Filter by assignment status */
11250
+ status?: "active" | "scheduled" | "expired";
11251
+ /** @description Filter by source node ID */
11252
+ source_node_id?: string;
11253
+ };
11254
+ header?: never;
11255
+ path: {
11256
+ id: string;
11257
+ nodeId: string;
11258
+ };
11259
+ cookie?: never;
11260
+ };
11261
+ requestBody?: never;
11262
+ responses: {
11263
+ /** @description Assignments returned */
11264
+ 200: {
11265
+ headers: {
11266
+ [name: string]: unknown;
11267
+ };
11268
+ content: {
11269
+ "application/json": {
11270
+ items: components["schemas"]["IdentityAssignmentRowDto"][];
11271
+ pagination: components["schemas"]["PageMetaDto"];
11272
+ };
11273
+ };
11274
+ };
11275
+ /** @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 */
11276
+ 400: {
11277
+ headers: {
11278
+ [name: string]: unknown;
11279
+ };
11280
+ content: {
11281
+ /**
11282
+ * @example {
11283
+ * "error": {
11284
+ * "statusCode": 400,
11285
+ * "code": null,
11286
+ * "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",
11287
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11288
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/access",
11289
+ * "method": "GET"
11290
+ * }
11291
+ * }
11292
+ */
11293
+ "application/json": components["schemas"]["ErrorResponseDto"];
11294
+ };
11295
+ };
11296
+ /** @description Invalid or expired token */
11297
+ 401: {
11298
+ headers: {
11299
+ [name: string]: unknown;
11300
+ };
11301
+ content: {
11302
+ /**
11303
+ * @example {
11304
+ * "error": {
11305
+ * "statusCode": 401,
11306
+ * "code": null,
11307
+ * "message": "Invalid or expired token",
11308
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11309
+ * "path": "/api/v1/organizations/{id}/me",
11310
+ * "method": "GET"
11311
+ * }
11312
+ * }
11313
+ */
11314
+ "application/json": components["schemas"]["ErrorResponseDto"];
11315
+ };
11316
+ };
11317
+ /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
11318
+ 403: {
11319
+ headers: {
11320
+ [name: string]: unknown;
11321
+ };
11322
+ content: {
11323
+ /**
11324
+ * @example {
11325
+ * "error": {
11326
+ * "statusCode": 403,
11327
+ * "code": null,
11328
+ * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
11329
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11330
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/access",
11331
+ * "method": "GET"
11332
+ * }
11333
+ * }
11334
+ */
11335
+ "application/json": components["schemas"]["ErrorResponseDto"];
11336
+ };
11337
+ };
11338
+ /** @description The organization is not in this Environment, or the node is not inside it */
11339
+ 404: {
11340
+ headers: {
11341
+ [name: string]: unknown;
11342
+ };
11343
+ content: {
11344
+ /**
11345
+ * @example {
11346
+ * "error": {
11347
+ * "statusCode": 404,
11348
+ * "code": null,
11349
+ * "message": "The organization is not in this Environment, or the node is not inside it",
11350
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11351
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/access",
11352
+ * "method": "GET"
11353
+ * }
11354
+ * }
11355
+ */
11356
+ "application/json": components["schemas"]["ErrorResponseDto"];
11357
+ };
11358
+ };
11359
+ };
11360
+ };
11361
+ ApiOrganizationAccessController_accessSummary: {
11362
+ parameters: {
11363
+ query?: never;
11364
+ header?: never;
11365
+ path: {
11366
+ id: string;
11367
+ nodeId: string;
11368
+ };
11369
+ cookie?: never;
11370
+ };
11371
+ requestBody?: never;
11372
+ responses: {
11373
+ /** @description Summary returned */
11374
+ 200: {
11375
+ headers: {
11376
+ [name: string]: unknown;
11377
+ };
11378
+ content: {
11379
+ "application/json": {
11380
+ data: components["schemas"]["NodeIdentitiesSummaryDto"];
11381
+ };
11382
+ };
11383
+ };
11384
+ /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
11385
+ 400: {
11386
+ headers: {
11387
+ [name: string]: unknown;
11388
+ };
11389
+ content: {
11390
+ /**
11391
+ * @example {
11392
+ * "error": {
11393
+ * "statusCode": 400,
11394
+ * "code": null,
11395
+ * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
11396
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11397
+ * "path": "/api/v1/organizations/{id}/me",
11398
+ * "method": "GET"
11399
+ * }
11400
+ * }
11401
+ */
11402
+ "application/json": components["schemas"]["ErrorResponseDto"];
11403
+ };
11404
+ };
11405
+ /** @description Invalid or expired token */
11406
+ 401: {
11407
+ headers: {
11408
+ [name: string]: unknown;
11409
+ };
11410
+ content: {
11411
+ /**
11412
+ * @example {
11413
+ * "error": {
11414
+ * "statusCode": 401,
11415
+ * "code": null,
11416
+ * "message": "Invalid or expired token",
11417
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11418
+ * "path": "/api/v1/organizations/{id}/me",
11419
+ * "method": "GET"
11420
+ * }
11421
+ * }
11422
+ */
11423
+ "application/json": components["schemas"]["ErrorResponseDto"];
11424
+ };
11425
+ };
11426
+ /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
11427
+ 403: {
11428
+ headers: {
11429
+ [name: string]: unknown;
11430
+ };
11431
+ content: {
11432
+ /**
11433
+ * @example {
11434
+ * "error": {
11435
+ * "statusCode": 403,
11436
+ * "code": null,
11437
+ * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
11438
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11439
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/access",
11440
+ * "method": "GET"
11441
+ * }
11442
+ * }
11443
+ */
11444
+ "application/json": components["schemas"]["ErrorResponseDto"];
11445
+ };
11446
+ };
11447
+ /** @description The organization is not in this Environment, or the node is not inside it */
11448
+ 404: {
11449
+ headers: {
11450
+ [name: string]: unknown;
11451
+ };
11452
+ content: {
11453
+ /**
11454
+ * @example {
11455
+ * "error": {
11456
+ * "statusCode": 404,
11457
+ * "code": null,
11458
+ * "message": "The organization is not in this Environment, or the node is not inside it",
11459
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11460
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/access/summary",
11461
+ * "method": "GET"
11462
+ * }
11463
+ * }
11464
+ */
11465
+ "application/json": components["schemas"]["ErrorResponseDto"];
11466
+ };
11467
+ };
11468
+ };
11469
+ };
11470
+ ApiOrganizationAccessController_grantableRoles: {
11471
+ parameters: {
11472
+ query?: never;
11473
+ header?: never;
11474
+ path: {
11475
+ id: string;
11476
+ nodeId: string;
11477
+ };
11478
+ cookie?: never;
11479
+ };
11480
+ requestBody?: never;
11481
+ responses: {
11482
+ /** @description Roles returned */
11483
+ 200: {
11484
+ headers: {
11485
+ [name: string]: unknown;
11486
+ };
11487
+ content: {
11488
+ "application/json": {
11489
+ items: components["schemas"]["RoleResponseDto"][];
11490
+ };
11491
+ };
11492
+ };
11493
+ /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
11494
+ 400: {
11495
+ headers: {
11496
+ [name: string]: unknown;
11497
+ };
11498
+ content: {
11499
+ /**
11500
+ * @example {
11501
+ * "error": {
11502
+ * "statusCode": 400,
11503
+ * "code": null,
11504
+ * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
11505
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11506
+ * "path": "/api/v1/organizations/{id}/me",
11507
+ * "method": "GET"
11508
+ * }
11509
+ * }
11510
+ */
11511
+ "application/json": components["schemas"]["ErrorResponseDto"];
11512
+ };
11513
+ };
11514
+ /** @description Invalid or expired token */
11515
+ 401: {
11516
+ headers: {
11517
+ [name: string]: unknown;
11518
+ };
11519
+ content: {
11520
+ /**
11521
+ * @example {
11522
+ * "error": {
11523
+ * "statusCode": 401,
11524
+ * "code": null,
11525
+ * "message": "Invalid or expired token",
11526
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11527
+ * "path": "/api/v1/organizations/{id}/me",
11528
+ * "method": "GET"
11529
+ * }
11530
+ * }
11531
+ */
11532
+ "application/json": components["schemas"]["ErrorResponseDto"];
11533
+ };
11534
+ };
11535
+ /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
11536
+ 403: {
11537
+ headers: {
11538
+ [name: string]: unknown;
11539
+ };
11540
+ content: {
11541
+ /**
11542
+ * @example {
11543
+ * "error": {
11544
+ * "statusCode": 403,
11545
+ * "code": null,
11546
+ * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
11547
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11548
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/access",
11549
+ * "method": "GET"
11550
+ * }
11551
+ * }
11552
+ */
11553
+ "application/json": components["schemas"]["ErrorResponseDto"];
11554
+ };
11555
+ };
11556
+ /** @description The organization is not in this Environment, or the node is not inside it */
11557
+ 404: {
11558
+ headers: {
11559
+ [name: string]: unknown;
11560
+ };
11561
+ content: {
11562
+ /**
11563
+ * @example {
11564
+ * "error": {
11565
+ * "statusCode": 404,
11566
+ * "code": null,
11567
+ * "message": "The organization is not in this Environment, or the node is not inside it",
11568
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11569
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/grantable-roles",
11570
+ * "method": "GET"
11571
+ * }
11572
+ * }
11573
+ */
11574
+ "application/json": components["schemas"]["ErrorResponseDto"];
11575
+ };
11576
+ };
11577
+ };
11578
+ };
11579
+ ApiOrganizationAccessController_listMembersAt: {
11580
+ parameters: {
11581
+ query?: {
11582
+ /** @description Page number (1-based) */
11583
+ page?: number;
11584
+ /** @description Items per page (1-100, default 20) */
11585
+ take?: number;
11586
+ /** @description Search member names and emails */
11587
+ q?: string;
11588
+ /** @description Sort column. Defaults to `joined`, longest-standing member first. */
11589
+ sort_by?: "name" | "email" | "joined";
11590
+ /** @description Sort direction */
11591
+ order?: "asc" | "desc";
11592
+ };
11593
+ header?: never;
11594
+ path: {
11595
+ id: string;
11596
+ nodeId: string;
11597
+ };
11598
+ cookie?: never;
11599
+ };
11600
+ requestBody?: never;
11601
+ responses: {
11602
+ /** @description Members returned */
11603
+ 200: {
11604
+ headers: {
11605
+ [name: string]: unknown;
11606
+ };
11607
+ content: {
11608
+ "application/json": {
11609
+ items: components["schemas"]["OrganizationMemberCandidateResponseDto"][];
11610
+ pagination: components["schemas"]["PageMetaDto"];
11611
+ };
11612
+ };
11613
+ };
11614
+ /** @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 */
11615
+ 400: {
11616
+ headers: {
11617
+ [name: string]: unknown;
11618
+ };
11619
+ content: {
11620
+ /**
11621
+ * @example {
11622
+ * "error": {
11623
+ * "statusCode": 400,
11624
+ * "code": null,
11625
+ * "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",
11626
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11627
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/members",
11628
+ * "method": "GET"
11629
+ * }
11630
+ * }
11631
+ */
11632
+ "application/json": components["schemas"]["ErrorResponseDto"];
11633
+ };
11634
+ };
11635
+ /** @description Invalid or expired token */
11636
+ 401: {
11637
+ headers: {
11638
+ [name: string]: unknown;
11639
+ };
11640
+ content: {
11641
+ /**
11642
+ * @example {
11643
+ * "error": {
11644
+ * "statusCode": 401,
11645
+ * "code": null,
11646
+ * "message": "Invalid or expired token",
11647
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11648
+ * "path": "/api/v1/organizations/{id}/me",
11649
+ * "method": "GET"
11650
+ * }
11651
+ * }
11652
+ */
11653
+ "application/json": components["schemas"]["ErrorResponseDto"];
11654
+ };
11655
+ };
11656
+ /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
11657
+ 403: {
11658
+ headers: {
11659
+ [name: string]: unknown;
11660
+ };
11661
+ content: {
11662
+ /**
11663
+ * @example {
11664
+ * "error": {
11665
+ * "statusCode": 403,
11666
+ * "code": null,
11667
+ * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
11668
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11669
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/access",
11670
+ * "method": "GET"
11671
+ * }
11672
+ * }
11673
+ */
11674
+ "application/json": components["schemas"]["ErrorResponseDto"];
11675
+ };
11676
+ };
11677
+ /** @description The organization is not in this Environment, or the node is not inside it */
11678
+ 404: {
11679
+ headers: {
11680
+ [name: string]: unknown;
11681
+ };
11682
+ content: {
11683
+ /**
11684
+ * @example {
11685
+ * "error": {
11686
+ * "statusCode": 404,
11687
+ * "code": null,
11688
+ * "message": "The organization is not in this Environment, or the node is not inside it",
11689
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11690
+ * "path": "/api/v1/organizations/{id}/nodes/{nodeId}/members",
11691
+ * "method": "GET"
11692
+ * }
11693
+ * }
11694
+ */
11695
+ "application/json": components["schemas"]["ErrorResponseDto"];
11696
+ };
11697
+ };
11698
+ };
11699
+ };
11700
+ ApiOrganizationAccessController_createAssignment: {
11701
+ parameters: {
11702
+ query?: never;
11703
+ header?: never;
11704
+ path: {
11705
+ id: string;
11706
+ };
11707
+ cookie?: never;
11708
+ };
11709
+ requestBody: {
11710
+ content: {
11711
+ "application/json": components["schemas"]["CreateOrganizationAssignmentDto"];
11712
+ };
11713
+ };
11714
+ responses: {
11715
+ /** @description Assignment created */
11716
+ 201: {
11717
+ headers: {
11718
+ [name: string]: unknown;
11719
+ };
11720
+ content: {
11721
+ "application/json": {
11722
+ data: components["schemas"]["AssignmentResponseDto"];
11723
+ };
11724
+ };
11725
+ };
11726
+ /** @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 */
11727
+ 400: {
11728
+ headers: {
11729
+ [name: string]: unknown;
11730
+ };
11731
+ content: {
11732
+ /**
11733
+ * @example {
11734
+ * "error": {
11735
+ * "statusCode": 400,
11736
+ * "code": null,
11737
+ * "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",
11738
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11739
+ * "path": "/api/v1/organizations/{id}/assignments",
11740
+ * "method": "POST"
11741
+ * }
11742
+ * }
11743
+ */
11744
+ "application/json": components["schemas"]["ErrorResponseDto"];
11745
+ };
11746
+ };
11747
+ /** @description Invalid or expired token */
11748
+ 401: {
11749
+ headers: {
11750
+ [name: string]: unknown;
11751
+ };
11752
+ content: {
11753
+ /**
11754
+ * @example {
11755
+ * "error": {
11756
+ * "statusCode": 401,
11757
+ * "code": null,
11758
+ * "message": "Invalid or expired token",
11759
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11760
+ * "path": "/api/v1/organizations/{id}/me",
11761
+ * "method": "GET"
11762
+ * }
11763
+ * }
11764
+ */
11765
+ "application/json": components["schemas"]["ErrorResponseDto"];
11766
+ };
11767
+ };
11768
+ /** @description The token is not an admin, API key or identity token, or the caller holds none of the keys the operation needs at the node, or is an identity outside the grant ceiling for the role (`assignment.grant_ceiling`) */
11769
+ 403: {
11770
+ headers: {
11771
+ [name: string]: unknown;
11772
+ };
11773
+ content: {
11774
+ /**
11775
+ * @example {
11776
+ * "error": {
11777
+ * "statusCode": 403,
11778
+ * "code": null,
11779
+ * "message": "The token is not an admin, API key or identity token, or the caller holds none of the keys the operation needs at the node, or is an identity outside the grant ceiling for the role (`assignment.grant_ceiling`)",
11780
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11781
+ * "path": "/api/v1/organizations/{id}/assignments",
11782
+ * "method": "POST"
11783
+ * }
11784
+ * }
11785
+ */
11786
+ "application/json": components["schemas"]["ErrorResponseDto"];
11787
+ };
11788
+ };
11789
+ /** @description The organization is not in this Environment, or the node is not inside it */
11790
+ 404: {
11791
+ headers: {
11792
+ [name: string]: unknown;
11793
+ };
11794
+ content: {
11795
+ /**
11796
+ * @example {
11797
+ * "error": {
11798
+ * "statusCode": 404,
11799
+ * "code": null,
11800
+ * "message": "The organization is not in this Environment, or the node is not inside it",
11801
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11802
+ * "path": "/api/v1/organizations/{id}/assignments",
11803
+ * "method": "POST"
11804
+ * }
11805
+ * }
11806
+ */
11807
+ "application/json": components["schemas"]["ErrorResponseDto"];
11808
+ };
11809
+ };
11810
+ /** @description The identity already holds this role at this node, or is not a member of the organization (`organization.membership_required`) */
11811
+ 409: {
11812
+ headers: {
11813
+ [name: string]: unknown;
11814
+ };
11815
+ content: {
11816
+ /**
11817
+ * @example {
11818
+ * "error": {
11819
+ * "statusCode": 409,
11820
+ * "code": null,
11821
+ * "message": "The identity already holds this role at this node, or is not a member of the organization (`organization.membership_required`)",
11822
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11823
+ * "path": "/api/v1/organizations/{id}/assignments",
11824
+ * "method": "POST"
11825
+ * }
11826
+ * }
11827
+ */
11828
+ "application/json": components["schemas"]["ErrorResponseDto"];
11829
+ };
11830
+ };
11831
+ };
11832
+ };
11833
+ ApiOrganizationAccessController_removeAssignment: {
11834
+ parameters: {
11835
+ query?: never;
11836
+ header?: never;
11837
+ path: {
11838
+ id: string;
11839
+ assignmentId: string;
11840
+ };
11841
+ cookie?: never;
11842
+ };
11843
+ requestBody?: never;
11844
+ responses: {
11845
+ /** @description Assignment removed */
11846
+ 204: {
11847
+ headers: {
11848
+ [name: string]: unknown;
11849
+ };
11850
+ content?: never;
11851
+ };
11852
+ /** @description The request sent both an `X-API-Key` and an `Authorization` header; send one */
11853
+ 400: {
11854
+ headers: {
11855
+ [name: string]: unknown;
11856
+ };
11857
+ content: {
11858
+ /**
11859
+ * @example {
11860
+ * "error": {
11861
+ * "statusCode": 400,
11862
+ * "code": null,
11863
+ * "message": "The request sent both an `X-API-Key` and an `Authorization` header; send one",
11864
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11865
+ * "path": "/api/v1/organizations/{id}/me",
11866
+ * "method": "GET"
11867
+ * }
11868
+ * }
11869
+ */
11870
+ "application/json": components["schemas"]["ErrorResponseDto"];
11871
+ };
11872
+ };
11873
+ /** @description Invalid or expired token */
11874
+ 401: {
11875
+ headers: {
11876
+ [name: string]: unknown;
11877
+ };
11878
+ content: {
11879
+ /**
11880
+ * @example {
11881
+ * "error": {
11882
+ * "statusCode": 401,
11883
+ * "code": null,
11884
+ * "message": "Invalid or expired token",
11885
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11886
+ * "path": "/api/v1/organizations/{id}/me",
11887
+ * "method": "GET"
11888
+ * }
11889
+ * }
11890
+ */
11891
+ "application/json": components["schemas"]["ErrorResponseDto"];
11892
+ };
11893
+ };
11894
+ /** @description The token is not an admin, API key or identity token, or the caller holds none of the keys the operation needs at the node */
11895
+ 403: {
11896
+ headers: {
11897
+ [name: string]: unknown;
11898
+ };
11899
+ content: {
11900
+ /**
11901
+ * @example {
11902
+ * "error": {
11903
+ * "statusCode": 403,
11904
+ * "code": null,
11905
+ * "message": "The token is not an admin, API key or identity token, or the caller holds none of the keys the operation needs at the node",
11906
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11907
+ * "path": "/api/v1/organizations/{id}/assignments/{assignmentId}",
11908
+ * "method": "DELETE"
11909
+ * }
11910
+ * }
11911
+ */
11912
+ "application/json": components["schemas"]["ErrorResponseDto"];
11913
+ };
11914
+ };
11915
+ /** @description The organization is not in this Environment, or the assignment is not at one of its nodes */
11916
+ 404: {
11917
+ headers: {
11918
+ [name: string]: unknown;
11919
+ };
11920
+ content: {
11921
+ /**
11922
+ * @example {
11923
+ * "error": {
11924
+ * "statusCode": 404,
11925
+ * "code": null,
11926
+ * "message": "The organization is not in this Environment, or the assignment is not at one of its nodes",
11927
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11928
+ * "path": "/api/v1/organizations/{id}/assignments/{assignmentId}",
11929
+ * "method": "DELETE"
11930
+ * }
11931
+ * }
11932
+ */
11933
+ "application/json": components["schemas"]["ErrorResponseDto"];
11934
+ };
11935
+ };
11936
+ /** @description The member is the organization's last administrator (`organization.last_admin`); make someone else one first */
11937
+ 409: {
11938
+ headers: {
11939
+ [name: string]: unknown;
11940
+ };
11941
+ content: {
11942
+ /**
11943
+ * @example {
11944
+ * "error": {
11945
+ * "statusCode": 409,
11946
+ * "code": null,
11947
+ * "message": "The member is the organization's last administrator (`organization.last_admin`); make someone else one first",
11948
+ * "timestamp": "2026-04-20T12:00:00.000Z",
11949
+ * "path": "/api/v1/organizations/{id}/assignments/{assignmentId}",
11950
+ * "method": "DELETE"
11951
+ * }
11952
+ * }
11953
+ */
11954
+ "application/json": components["schemas"]["ErrorResponseDto"];
11955
+ };
11956
+ };
11957
+ };
11958
+ };
11959
+ ApiOrganizationAccessController_updateAssignment: {
11960
+ parameters: {
11961
+ query?: never;
11962
+ header?: {
11963
+ /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
11964
+ "If-Match"?: string;
11965
+ };
11966
+ path: {
11967
+ id: string;
11968
+ assignmentId: string;
11969
+ };
11970
+ cookie?: never;
11971
+ };
11972
+ requestBody: {
11973
+ content: {
11974
+ "application/json": components["schemas"]["UpdateAssignmentDto"];
11975
+ };
11976
+ };
11977
+ responses: {
11978
+ /** @description Assignment updated */
11979
+ 200: {
11980
+ headers: {
11981
+ [name: string]: unknown;
11982
+ };
11983
+ content: {
11984
+ "application/json": {
11985
+ data: components["schemas"]["AssignmentResponseDto"];
11986
+ };
11987
+ };
11988
+ };
11989
+ /** @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 */
11990
+ 400: {
11991
+ headers: {
11992
+ [name: string]: unknown;
11993
+ };
11994
+ content: {
11995
+ /**
11996
+ * @example {
11997
+ * "error": {
11998
+ * "statusCode": 400,
11999
+ * "code": null,
12000
+ * "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",
12001
+ * "timestamp": "2026-04-20T12:00:00.000Z",
12002
+ * "path": "/api/v1/organizations/{id}/assignments/{assignmentId}",
12003
+ * "method": "PATCH"
12004
+ * }
12005
+ * }
12006
+ */
12007
+ "application/json": components["schemas"]["ErrorResponseDto"];
12008
+ };
12009
+ };
12010
+ /** @description Invalid or expired token */
12011
+ 401: {
12012
+ headers: {
12013
+ [name: string]: unknown;
12014
+ };
12015
+ content: {
12016
+ /**
12017
+ * @example {
12018
+ * "error": {
12019
+ * "statusCode": 401,
12020
+ * "code": null,
12021
+ * "message": "Invalid or expired token",
12022
+ * "timestamp": "2026-04-20T12:00:00.000Z",
12023
+ * "path": "/api/v1/organizations/{id}/me",
12024
+ * "method": "GET"
12025
+ * }
12026
+ * }
12027
+ */
12028
+ "application/json": components["schemas"]["ErrorResponseDto"];
12029
+ };
12030
+ };
12031
+ /** @description The token is not an admin, API key or identity token, or the caller holds none of the keys the operation needs at the node, or is an identity outside the grant ceiling for the role (`assignment.grant_ceiling`) */
12032
+ 403: {
10544
12033
  headers: {
10545
12034
  [name: string]: unknown;
10546
12035
  };
@@ -10548,20 +12037,20 @@ interface operations {
10548
12037
  /**
10549
12038
  * @example {
10550
12039
  * "error": {
10551
- * "statusCode": 401,
12040
+ * "statusCode": 403,
10552
12041
  * "code": null,
10553
- * "message": "Invalid or expired token",
12042
+ * "message": "The token is not an admin, API key or identity token, or the caller holds none of the keys the operation needs at the node, or is an identity outside the grant ceiling for the role (`assignment.grant_ceiling`)",
10554
12043
  * "timestamp": "2026-04-20T12:00:00.000Z",
10555
- * "path": "/api/v1/nodes",
10556
- * "method": "GET"
12044
+ * "path": "/api/v1/organizations/{id}/assignments/{assignmentId}",
12045
+ * "method": "PATCH"
10557
12046
  * }
10558
12047
  * }
10559
12048
  */
10560
12049
  "application/json": components["schemas"]["ErrorResponseDto"];
10561
12050
  };
10562
12051
  };
10563
- /** @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 */
10564
- 403: {
12052
+ /** @description The organization is not in this Environment, or the assignment is not at one of its nodes */
12053
+ 404: {
10565
12054
  headers: {
10566
12055
  [name: string]: unknown;
10567
12056
  };
@@ -10569,20 +12058,20 @@ interface operations {
10569
12058
  /**
10570
12059
  * @example {
10571
12060
  * "error": {
10572
- * "statusCode": 403,
12061
+ * "statusCode": 404,
10573
12062
  * "code": null,
10574
- * "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",
12063
+ * "message": "The organization is not in this Environment, or the assignment is not at one of its nodes",
10575
12064
  * "timestamp": "2026-04-20T12:00:00.000Z",
10576
- * "path": "/api/v1/nodes",
10577
- * "method": "GET"
12065
+ * "path": "/api/v1/organizations/{id}/assignments/{assignmentId}",
12066
+ * "method": "PATCH"
10578
12067
  * }
10579
12068
  * }
10580
12069
  */
10581
12070
  "application/json": components["schemas"]["ErrorResponseDto"];
10582
12071
  };
10583
12072
  };
10584
- /** @description Node not found */
10585
- 404: {
12073
+ /** @description The identity already holds this role at this node, the assignment has been modified since the version named in If-Match was read (`assignment.version_mismatch`), or it is the last administrator's role at the organization node (`organization.last_admin`) */
12074
+ 409: {
10586
12075
  headers: {
10587
12076
  [name: string]: unknown;
10588
12077
  };
@@ -10590,12 +12079,12 @@ interface operations {
10590
12079
  /**
10591
12080
  * @example {
10592
12081
  * "error": {
10593
- * "statusCode": 404,
12082
+ * "statusCode": 409,
10594
12083
  * "code": null,
10595
- * "message": "Node not found",
12084
+ * "message": "The identity already holds this role at this node, the assignment has been modified since the version named in If-Match was read (`assignment.version_mismatch`), or it is the last administrator's role at the organization node (`organization.last_admin`)",
10596
12085
  * "timestamp": "2026-04-20T12:00:00.000Z",
10597
- * "path": "/api/v1/nodes/{id}/identities/summary",
10598
- * "method": "GET"
12086
+ * "path": "/api/v1/organizations/{id}/assignments/{assignmentId}",
12087
+ * "method": "PATCH"
10599
12088
  * }
10600
12089
  * }
10601
12090
  */
@@ -11005,8 +12494,7 @@ interface operations {
11005
12494
  ApiOrganizationsController_deleteOrganization: {
11006
12495
  parameters: {
11007
12496
  query?: never;
11008
- header: {
11009
- "if-match": string;
12497
+ header?: {
11010
12498
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
11011
12499
  "If-Match"?: string;
11012
12500
  };
@@ -11134,8 +12622,7 @@ interface operations {
11134
12622
  ApiOrganizationsController_updateOrganization: {
11135
12623
  parameters: {
11136
12624
  query?: never;
11137
- header: {
11138
- "if-match": string;
12625
+ header?: {
11139
12626
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
11140
12627
  "If-Match"?: string;
11141
12628
  };
@@ -11379,8 +12866,7 @@ interface operations {
11379
12866
  ApiOrganizationsController_updatePolicy: {
11380
12867
  parameters: {
11381
12868
  query?: never;
11382
- header: {
11383
- "if-match": string;
12869
+ header?: {
11384
12870
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
11385
12871
  "If-Match"?: string;
11386
12872
  };
@@ -12690,14 +14176,14 @@ interface operations {
12690
14176
  take?: number;
12691
14177
  /** @description Search member names and emails */
12692
14178
  q?: string;
12693
- /** @description Sort column. Defaults to `created`, oldest membership first. */
12694
- sort_by?: "name" | "email" | "role" | "created";
14179
+ /** @description Sort column. Defaults to `joined`, longest-standing member first. */
14180
+ sort_by?: "name" | "email" | "joined";
12695
14181
  /** @description Sort direction */
12696
14182
  order?: "asc" | "desc";
12697
- /** @description Only members holding this role */
14183
+ /** @description Only members holding this role anywhere in the organization, at its node or beneath */
12698
14184
  role_id?: string;
12699
- /** @description Filter by the membership's effective window: active now, scheduled to start, or already expired */
12700
- status?: "active" | "scheduled" | "expired";
14185
+ /** @description Which memberships to list: `active` (the default), `deactivated` for members who left, or `all` */
14186
+ status?: "active" | "deactivated" | "all";
12701
14187
  };
12702
14188
  header?: never;
12703
14189
  path: {
@@ -12915,7 +14401,7 @@ interface operations {
12915
14401
  "application/json": components["schemas"]["ErrorResponseDto"];
12916
14402
  };
12917
14403
  };
12918
- /** @description The identity is already a member of this organization */
14404
+ /** @description The identity is already a member of this organization (`organization.member_exists`); give them a role through the assignment routes */
12919
14405
  409: {
12920
14406
  headers: {
12921
14407
  [name: string]: unknown;
@@ -12926,7 +14412,7 @@ interface operations {
12926
14412
  * "error": {
12927
14413
  * "statusCode": 409,
12928
14414
  * "code": null,
12929
- * "message": "The identity is already a member of this organization",
14415
+ * "message": "The identity is already a member of this organization (`organization.member_exists`); give them a role through the assignment routes",
12930
14416
  * "timestamp": "2026-04-20T12:00:00.000Z",
12931
14417
  * "path": "/api/v1/organizations/{id}/members",
12932
14418
  * "method": "POST"
@@ -13064,140 +14550,6 @@ interface operations {
13064
14550
  };
13065
14551
  };
13066
14552
  };
13067
- ApiOrganizationsController_changeMemberRole: {
13068
- parameters: {
13069
- query?: never;
13070
- header?: never;
13071
- path: {
13072
- id: string;
13073
- identityId: string;
13074
- };
13075
- cookie?: never;
13076
- };
13077
- requestBody: {
13078
- content: {
13079
- "application/json": components["schemas"]["ChangeOrganizationMemberRoleDto"];
13080
- };
13081
- };
13082
- responses: {
13083
- /** @description Member role changed */
13084
- 200: {
13085
- headers: {
13086
- [name: string]: unknown;
13087
- };
13088
- content: {
13089
- "application/json": {
13090
- data: components["schemas"]["OrganizationMemberResponseDto"];
13091
- };
13092
- };
13093
- };
13094
- /** @description The request failed validation, or the role is inactive or a system role; or the request sent both an `X-API-Key` and an `Authorization` header */
13095
- 400: {
13096
- headers: {
13097
- [name: string]: unknown;
13098
- };
13099
- content: {
13100
- /**
13101
- * @example {
13102
- * "error": {
13103
- * "statusCode": 400,
13104
- * "code": null,
13105
- * "message": "The request failed validation, or the role is inactive or a system role; or the request sent both an `X-API-Key` and an `Authorization` header",
13106
- * "timestamp": "2026-04-20T12:00:00.000Z",
13107
- * "path": "/api/v1/organizations/{id}/members/{identityId}",
13108
- * "method": "PATCH"
13109
- * }
13110
- * }
13111
- */
13112
- "application/json": components["schemas"]["ErrorResponseDto"];
13113
- };
13114
- };
13115
- /** @description Invalid or expired token */
13116
- 401: {
13117
- headers: {
13118
- [name: string]: unknown;
13119
- };
13120
- content: {
13121
- /**
13122
- * @example {
13123
- * "error": {
13124
- * "statusCode": 401,
13125
- * "code": null,
13126
- * "message": "Invalid or expired token",
13127
- * "timestamp": "2026-04-20T12:00:00.000Z",
13128
- * "path": "/api/v1/organizations",
13129
- * "method": "GET"
13130
- * }
13131
- * }
13132
- */
13133
- "application/json": components["schemas"]["ErrorResponseDto"];
13134
- };
13135
- };
13136
- /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
13137
- 403: {
13138
- headers: {
13139
- [name: string]: unknown;
13140
- };
13141
- content: {
13142
- /**
13143
- * @example {
13144
- * "error": {
13145
- * "statusCode": 403,
13146
- * "code": null,
13147
- * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
13148
- * "timestamp": "2026-04-20T12:00:00.000Z",
13149
- * "path": "/api/v1/organizations",
13150
- * "method": "GET"
13151
- * }
13152
- * }
13153
- */
13154
- "application/json": components["schemas"]["ErrorResponseDto"];
13155
- };
13156
- };
13157
- /** @description The organization or the role does not exist, or the identity is not a member of this organization */
13158
- 404: {
13159
- headers: {
13160
- [name: string]: unknown;
13161
- };
13162
- content: {
13163
- /**
13164
- * @example {
13165
- * "error": {
13166
- * "statusCode": 404,
13167
- * "code": null,
13168
- * "message": "The organization or the role does not exist, or the identity is not a member of this organization",
13169
- * "timestamp": "2026-04-20T12:00:00.000Z",
13170
- * "path": "/api/v1/organizations/{id}/members/{identityId}",
13171
- * "method": "PATCH"
13172
- * }
13173
- * }
13174
- */
13175
- "application/json": components["schemas"]["ErrorResponseDto"];
13176
- };
13177
- };
13178
- /** @description The member is the organization's last administrator (`organization.last_admin`); make someone else one first */
13179
- 409: {
13180
- headers: {
13181
- [name: string]: unknown;
13182
- };
13183
- content: {
13184
- /**
13185
- * @example {
13186
- * "error": {
13187
- * "statusCode": 409,
13188
- * "code": null,
13189
- * "message": "The member is the organization's last administrator (`organization.last_admin`); make someone else one first",
13190
- * "timestamp": "2026-04-20T12:00:00.000Z",
13191
- * "path": "/api/v1/organizations/{id}/members/{identityId}",
13192
- * "method": "PATCH"
13193
- * }
13194
- * }
13195
- */
13196
- "application/json": components["schemas"]["ErrorResponseDto"];
13197
- };
13198
- };
13199
- };
13200
- };
13201
14553
  ApiOrganizationsController_resetMemberMfa: {
13202
14554
  parameters: {
13203
14555
  query?: never;
@@ -13514,7 +14866,7 @@ interface operations {
13514
14866
  "application/json": components["schemas"]["ErrorResponseDto"];
13515
14867
  };
13516
14868
  };
13517
- /** @description This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa) */
14869
+ /** @description The token is not an admin, API key or identity token, or the caller is an identity that does not hold, at the organization node or above, every permission the role carries (`assignment.grant_ceiling`); Console users and API keys are not bounded */
13518
14870
  403: {
13519
14871
  headers: {
13520
14872
  [name: string]: unknown;
@@ -13525,10 +14877,10 @@ interface operations {
13525
14877
  * "error": {
13526
14878
  * "statusCode": 403,
13527
14879
  * "code": null,
13528
- * "message": "This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)",
14880
+ * "message": "The token is not an admin, API key or identity token, or the caller is an identity that does not hold, at the organization node or above, every permission the role carries (`assignment.grant_ceiling`); Console users and API keys are not bounded",
13529
14881
  * "timestamp": "2026-04-20T12:00:00.000Z",
13530
- * "path": "/api/v1/organizations",
13531
- * "method": "GET"
14882
+ * "path": "/api/v1/organizations/{id}/invites",
14883
+ * "method": "POST"
13532
14884
  * }
13533
14885
  * }
13534
14886
  */
@@ -13597,7 +14949,7 @@ interface operations {
13597
14949
  };
13598
14950
  content: {
13599
14951
  "application/json": {
13600
- items: components["schemas"]["RoleResponseDto"][];
14952
+ items: components["schemas"]["OrganizationRoleResponseDto"][];
13601
14953
  };
13602
14954
  };
13603
14955
  };
@@ -16871,8 +18223,7 @@ interface operations {
16871
18223
  ApiRolesController_deleteRole: {
16872
18224
  parameters: {
16873
18225
  query?: never;
16874
- header: {
16875
- "if-match": string;
18226
+ header?: {
16876
18227
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
16877
18228
  "If-Match"?: string;
16878
18229
  };
@@ -17000,8 +18351,7 @@ interface operations {
17000
18351
  ApiRolesController_updateRole: {
17001
18352
  parameters: {
17002
18353
  query?: never;
17003
- header: {
17004
- "if-match": string;
18354
+ header?: {
17005
18355
  /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
17006
18356
  "If-Match"?: string;
17007
18357
  };
@@ -17650,7 +19000,7 @@ interface operations {
17650
19000
  "application/json": components["schemas"]["ErrorResponseDto"];
17651
19001
  };
17652
19002
  };
17653
- /** @description The identity already has this role at this node, already holds its one role at this organization, or the node sits beneath an organization the identity has no membership in effect at */
19003
+ /** @description The identity already has this role at this node, or the node sits beneath an organization the identity is not an active member of (`organization.membership_required`) */
17654
19004
  409: {
17655
19005
  headers: {
17656
19006
  [name: string]: unknown;
@@ -17661,7 +19011,7 @@ interface operations {
17661
19011
  * "error": {
17662
19012
  * "statusCode": 409,
17663
19013
  * "code": null,
17664
- * "message": "The identity already has this role at this node, already holds its one role at this organization, or the node sits beneath an organization the identity has no membership in effect at",
19014
+ * "message": "The identity already has this role at this node, or the node sits beneath an organization the identity is not an active member of (`organization.membership_required`)",
17665
19015
  * "timestamp": "2026-04-20T12:00:00.000Z",
17666
19016
  * "path": "/api/v1/assignments",
17667
19017
  * "method": "POST"
@@ -17775,12 +19125,36 @@ interface operations {
17775
19125
  "application/json": components["schemas"]["ErrorResponseDto"];
17776
19126
  };
17777
19127
  };
19128
+ /** @description The member is the organization's last administrator (`organization.last_admin`); make someone else one first */
19129
+ 409: {
19130
+ headers: {
19131
+ [name: string]: unknown;
19132
+ };
19133
+ content: {
19134
+ /**
19135
+ * @example {
19136
+ * "error": {
19137
+ * "statusCode": 409,
19138
+ * "code": null,
19139
+ * "message": "The member is the organization's last administrator (`organization.last_admin`); make someone else one first",
19140
+ * "timestamp": "2026-04-20T12:00:00.000Z",
19141
+ * "path": "/api/v1/assignments/{id}",
19142
+ * "method": "DELETE"
19143
+ * }
19144
+ * }
19145
+ */
19146
+ "application/json": components["schemas"]["ErrorResponseDto"];
19147
+ };
19148
+ };
17778
19149
  };
17779
19150
  };
17780
19151
  ApiAssignmentsController_updateAssignment: {
17781
19152
  parameters: {
17782
19153
  query?: never;
17783
- header?: never;
19154
+ header?: {
19155
+ /** @description Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. */
19156
+ "If-Match"?: string;
19157
+ };
17784
19158
  path: {
17785
19159
  id: string;
17786
19160
  };
@@ -17887,7 +19261,7 @@ interface operations {
17887
19261
  "application/json": components["schemas"]["ErrorResponseDto"];
17888
19262
  };
17889
19263
  };
17890
- /** @description Identity already has this role at this node */
19264
+ /** @description The identity already holds this role at this node, the assignment has been modified since the version named in If-Match was read (`assignment.version_mismatch`), or the role is the last administrator's at an organization node (`organization.last_admin`) */
17891
19265
  409: {
17892
19266
  headers: {
17893
19267
  [name: string]: unknown;
@@ -17898,7 +19272,7 @@ interface operations {
17898
19272
  * "error": {
17899
19273
  * "statusCode": 409,
17900
19274
  * "code": null,
17901
- * "message": "Identity already has this role at this node",
19275
+ * "message": "The identity already holds this role at this node, the assignment has been modified since the version named in If-Match was read (`assignment.version_mismatch`), or the role is the last administrator's at an organization node (`organization.last_admin`)",
17902
19276
  * "timestamp": "2026-04-20T12:00:00.000Z",
17903
19277
  * "path": "/api/v1/assignments/{id}",
17904
19278
  * "method": "PATCH"
@@ -18014,6 +19388,27 @@ interface operations {
18014
19388
  "application/json": components["schemas"]["ErrorResponseDto"];
18015
19389
  };
18016
19390
  };
19391
+ /** @description The member is the organization's last administrator (`organization.last_admin`); make someone else one first */
19392
+ 409: {
19393
+ headers: {
19394
+ [name: string]: unknown;
19395
+ };
19396
+ content: {
19397
+ /**
19398
+ * @example {
19399
+ * "error": {
19400
+ * "statusCode": 409,
19401
+ * "code": null,
19402
+ * "message": "The member is the organization's last administrator (`organization.last_admin`); make someone else one first",
19403
+ * "timestamp": "2026-04-20T12:00:00.000Z",
19404
+ * "path": "/api/v1/assignments/bulk-remove",
19405
+ * "method": "POST"
19406
+ * }
19407
+ * }
19408
+ */
19409
+ "application/json": components["schemas"]["ErrorResponseDto"];
19410
+ };
19411
+ };
18017
19412
  };
18018
19413
  };
18019
19414
  ApiAssignmentsController_bulkChangeRole: {
@@ -18124,7 +19519,7 @@ interface operations {
18124
19519
  "application/json": components["schemas"]["ErrorResponseDto"];
18125
19520
  };
18126
19521
  };
18127
- /** @description Identity already has this role at this node */
19522
+ /** @description The identity already holds this role at this node, the assignment has been modified since the version named in If-Match was read (`assignment.version_mismatch`), or the role is the last administrator's at an organization node (`organization.last_admin`) */
18128
19523
  409: {
18129
19524
  headers: {
18130
19525
  [name: string]: unknown;
@@ -18135,7 +19530,7 @@ interface operations {
18135
19530
  * "error": {
18136
19531
  * "statusCode": 409,
18137
19532
  * "code": null,
18138
- * "message": "Identity already has this role at this node",
19533
+ * "message": "The identity already holds this role at this node, the assignment has been modified since the version named in If-Match was read (`assignment.version_mismatch`), or the role is the last administrator's at an organization node (`organization.last_admin`)",
18139
19534
  * "timestamp": "2026-04-20T12:00:00.000Z",
18140
19535
  * "path": "/api/v1/assignments/bulk-change-role",
18141
19536
  * "method": "POST"
@@ -19081,8 +20476,7 @@ interface operations {
19081
20476
  ApiHierarchySchemaController_updateSchema: {
19082
20477
  parameters: {
19083
20478
  query?: never;
19084
- header: {
19085
- "if-match": string;
20479
+ header?: {
19086
20480
  /** @description Optimistic-lock token. Pass the `version` you read from the Environment — request fails 409 when the row has moved on. */
19087
20481
  "If-Match"?: string;
19088
20482
  };
@@ -21486,7 +22880,12 @@ declare class Assignments {
21486
22880
  * answer, read the current assignments before retrying.
21487
22881
  */
21488
22882
  create(input: RequestBody<"ApiAssignmentsController_assignRole">): Promise<ResponseBody<"ApiAssignmentsController_assignRole">>;
21489
- update(id: string, input: RequestBody<"ApiAssignmentsController_updateAssignment">): Promise<ResponseBody<"ApiAssignmentsController_updateAssignment">>;
22883
+ /**
22884
+ * Change the role or the window of a grant. Pass the `version` the
22885
+ * assignment was read with as `ifMatch`; a stale one answers 409
22886
+ * `assignment.version_mismatch` rather than overwriting a newer change.
22887
+ */
22888
+ update(id: string, input: RequestBody<"ApiAssignmentsController_updateAssignment">, options?: ConcurrencyOptions): Promise<ResponseBody<"ApiAssignmentsController_updateAssignment">>;
21490
22889
  delete(id: string): Promise<void>;
21491
22890
  /**
21492
22891
  * Grant many at once. Answers 207 with a per-item result rather than failing
@@ -21539,7 +22938,18 @@ declare class Identities {
21539
22938
  * question at the node that matters. This is for showing a person what
21540
22939
  * someone can do.
21541
22940
  */
21542
- permissions(id: string): Promise<ResponseBody<"ApiIdentitiesController_getIdentityPermissions">>;
22941
+ permissions(id: string, query?: QueryParams<"ApiIdentitiesController_getIdentityPermissions">): Promise<ResponseBody<"ApiIdentitiesController_getIdentityPermissions">>;
22942
+ /**
22943
+ * Where the identity may act with one permission, answered by Canopy for a
22944
+ * list query: the minimal grant roots, and every node beneath them up to
22945
+ * `max_nodes` (null past it, with `complete: false`), or `env_wide` when a
22946
+ * root is the Environment's own root and no filter is needed.
22947
+ *
22948
+ * `LocalAuthorizer.accessibleNodes` answers the same question from its
22949
+ * cache without a call; this is the fresh answer, and the one for a process
22950
+ * that does not run the authorizer.
22951
+ */
22952
+ accessibleNodes(id: string, query: QueryParams<"ApiIdentitiesController_getIdentityAccessibleNodes">): Promise<ResponseBody<"ApiIdentitiesController_getIdentityAccessibleNodes">>;
21543
22953
  /**
21544
22954
  * Every session the identity holds that is neither revoked nor expired,
21545
22955
  * newest first: when and where it was signed in, when it expires, and the
@@ -21579,8 +22989,8 @@ type ItemOf$3<T> = T extends {
21579
22989
  } ? Item : never;
21580
22990
 
21581
22991
  /**
21582
- * Tenant organizations: one per business customer, a role per membership,
21583
- * each with its own authentication policy and identity provider. Every
22992
+ * Tenant organizations: one per business customer, membership apart from
22993
+ * the roles held inside it, each with its own authentication policy and identity provider. Every
21584
22994
  * call here needs the Environment's organizations container switched on.
21585
22995
  */
21586
22996
  declare class Organizations {
@@ -21605,8 +23015,12 @@ declare class Organizations {
21605
23015
  deleteAll(): Promise<void>;
21606
23016
  listMembers(id: string, query?: QueryParams<"ApiOrganizationsController_listMembers">): Paginator<OrganizationMemberItem>;
21607
23017
  addMember(id: string, input: RequestBody<"ApiOrganizationsController_addMember">): Promise<ResponseBody<"ApiOrganizationsController_addMember">>;
21608
- changeMemberRole(id: string, identityId: string, input: RequestBody<"ApiOrganizationsController_changeMemberRole">): Promise<ResponseBody<"ApiOrganizationsController_changeMemberRole">>;
21609
- /** Revokes that organization's one role; the identity and its other memberships are untouched. */
23018
+ /**
23019
+ * Deactivates the membership and revokes every role the member holds at
23020
+ * the organization's nodes; the identity and its other memberships are
23021
+ * untouched. A role in the organization is changed through the
23022
+ * organization's assignment routes, not here.
23023
+ */
21610
23024
  removeMember(id: string, identityId: string): Promise<void>;
21611
23025
  /**
21612
23026
  * Clears a member's second factor, for one who lost their authenticator:
@@ -21839,6 +23253,39 @@ declare class Canopy {
21839
23253
  * delay is short, so a longer value is refused rather than honoured.
21840
23254
  */
21841
23255
  declare const MAX_TTL_MS = 300000;
23256
+ /**
23257
+ * The largest node set `accessibleNodes` builds unless told otherwise. Past
23258
+ * it the answer carries the roots alone, and the caller filters against its
23259
+ * own closure table or materialised path instead of an `IN (...)` list.
23260
+ */
23261
+ declare const DEFAULT_MAX_NODES = 10000;
23262
+ /**
23263
+ * Why a check was denied, as far as the grant roots and the tree can say.
23264
+ *
23265
+ * - `permission_not_held`: no assignment grants the permission anywhere, in
23266
+ * effect or not.
23267
+ * - `outside_grants`: it is granted, but at no node on the lineage of the
23268
+ * node asked about.
23269
+ * - `expired`: a grant that would answer has ended, and none is in effect.
23270
+ * - `not_yet_effective`: a grant that would answer has not begun, and none
23271
+ * is in effect.
23272
+ * - `node_missing`: a `node` check named no node, which is a denial rather
23273
+ * than an error, because a request whose subject cannot be established
23274
+ * must not pass.
23275
+ */
23276
+ type LocalDenialReason = "permission_not_held" | "outside_grants" | "expired" | "not_yet_effective" | "node_missing";
23277
+ /** The answer to a check: the verdict, and why when it is no. */
23278
+ interface LocalDecision {
23279
+ allowed: boolean;
23280
+ reason: LocalDenialReason | null;
23281
+ }
23282
+ /** What a decision hook receives, after the verdict is in. */
23283
+ interface LocalDecisionEvent {
23284
+ query: LocalAuthorizationQuery;
23285
+ decision: LocalDecision;
23286
+ /** How long the check took, reads included. */
23287
+ durationMs: number;
23288
+ }
21842
23289
  interface LocalAuthorizerOptions {
21843
23290
  /**
21844
23291
  * How long grant roots and the hierarchy are reused, in milliseconds.
@@ -21871,6 +23318,19 @@ interface LocalAuthorizerOptions {
21871
23318
  timeoutMs?: number;
21872
23319
  /** Retries for those reads. */
21873
23320
  maxRetries?: number;
23321
+ /**
23322
+ * The largest node set {@link LocalAuthorizer.accessibleNodes} builds
23323
+ * unless a call says otherwise. Defaults to {@link DEFAULT_MAX_NODES}.
23324
+ */
23325
+ maxNodes?: number;
23326
+ /**
23327
+ * Called after every decision, allowed or not, with the question and the
23328
+ * answer. Never awaited and never allowed to fail the check: a hook that
23329
+ * throws is ignored. For audit trails and metrics.
23330
+ */
23331
+ onDecision?: (event: LocalDecisionEvent) => void;
23332
+ /** Called after every denial, the same way. For alerting on refusals. */
23333
+ onDenied?: (event: LocalDecisionEvent) => void;
21874
23334
  /** Injectable clock, for tests. */
21875
23335
  now?: () => number;
21876
23336
  }
@@ -21881,6 +23341,26 @@ interface LocalAuthorizationQuery {
21881
23341
  scope?: "node" | "app_wide";
21882
23342
  node_id?: string;
21883
23343
  }
23344
+ /** Where an identity may act with one permission, shaped for a list query. */
23345
+ interface AccessibleNodes {
23346
+ /**
23347
+ * The nodes the permission is granted at, in effect now, that no other
23348
+ * such node already covers. Each reaches everything beneath it.
23349
+ */
23350
+ roots: string[];
23351
+ /**
23352
+ * Every node beneath the roots, the roots included, for an `IN (...)`
23353
+ * filter. Null when `envWide`, or when the set would exceed the cap.
23354
+ */
23355
+ nodes: Set<string> | null;
23356
+ /** False when the set exceeded the cap and `nodes` was not built. */
23357
+ complete: boolean;
23358
+ /**
23359
+ * True when a root is the Environment's own root: every node qualifies, so
23360
+ * a list needs no filter at all.
23361
+ */
23362
+ envWide: boolean;
23363
+ }
21884
23364
  interface LocalAuthorizerStats {
21885
23365
  /** Reads of an identity's grant roots, one per refresh however many pages it took. */
21886
23366
  grantFetches: number;
@@ -21900,8 +23380,11 @@ interface LocalAuthorizerStats {
21900
23380
  declare class LocalAuthorizer {
21901
23381
  private readonly client;
21902
23382
  private readonly ttlMs;
23383
+ private readonly maxNodes;
21903
23384
  private readonly now;
21904
23385
  private readonly readOptions;
23386
+ private readonly onDecision;
23387
+ private readonly onDenied;
21905
23388
  private readonly grants;
21906
23389
  private tree;
21907
23390
  /**
@@ -21917,7 +23400,7 @@ declare class LocalAuthorizer {
21917
23400
  private stats;
21918
23401
  constructor(client: CanopyClient, options?: LocalAuthorizerOptions);
21919
23402
  /**
21920
- * Whether the identity holds the permission.
23403
+ * Whether the identity holds the permission, and why not when it does not.
21921
23404
  *
21922
23405
  * Shaped like the API's own evaluate so a caller can swap one for the other.
21923
23406
  * A `node` check with no node is a denial rather than an error: a request
@@ -21925,9 +23408,51 @@ declare class LocalAuthorizer {
21925
23408
  */
21926
23409
  evaluate(query: LocalAuthorizationQuery, options?: {
21927
23410
  signal?: AbortSignal;
21928
- }): Promise<{
21929
- allowed: boolean;
23411
+ }): Promise<LocalDecision>;
23412
+ /**
23413
+ * The nodes the identity holds the permission at, in effect now, reduced to
23414
+ * the ones no other such node already covers, and whether one of them is
23415
+ * the Environment's root. The roots alone are enough for an application
23416
+ * that keeps a closure table or a materialised path: it filters by "beneath
23417
+ * one of these" without an expanded set.
23418
+ *
23419
+ * Reads the tree, since minimality and `envWide` are questions about it; a
23420
+ * root the readable hierarchy does not contain raises
23421
+ * `authorizer.hierarchy_incomplete`, as a check at such a node does.
23422
+ */
23423
+ grantRoots(identityId: string, permission: string): Promise<{
23424
+ roots: string[];
23425
+ envWide: boolean;
21930
23426
  }>;
23427
+ /**
23428
+ * Where the identity may act with the permission, as the set a list query
23429
+ * filters by: {@link grantRoots} expanded through their descendants, up to
23430
+ * `maxNodes` (the authorizer's default unless given here).
23431
+ *
23432
+ * Past the cap `nodes` is null and `complete` false: the set is too large
23433
+ * to be worth an `IN (...)` list, and the caller filters by `roots`
23434
+ * instead. An `envWide` answer carries no set either, since every node
23435
+ * qualifies and a filter would only slow the query down.
23436
+ *
23437
+ * Computed from the same cached grant roots and tree a check uses, so a
23438
+ * list filtered by it and the check on a write cannot disagree, and it goes
23439
+ * stale on the same `ttlMs`.
23440
+ */
23441
+ accessibleNodes(identityId: string, permission: string, options?: {
23442
+ maxNodes?: number;
23443
+ }): Promise<AccessibleNodes>;
23444
+ /**
23445
+ * Every permission the identity holds at the node, by grant or by
23446
+ * inheritance: the list a screen renders its controls from, answered from
23447
+ * the same cached grant roots and tree a check uses.
23448
+ */
23449
+ permissionsAt(identityId: string, nodeId: string): Promise<string[]>;
23450
+ /**
23451
+ * {@link permissionsAt} for several nodes at once, as node → permissions:
23452
+ * the rows of a list each with their own controls, answered from one read
23453
+ * of the grant roots and one walk per node.
23454
+ */
23455
+ permissionsAtMany(identityId: string, nodeIds: readonly string[]): Promise<Map<string, string[]>>;
21931
23456
  private decide;
21932
23457
  /** Counters for observability — how much traffic the cache is actually saving. */
21933
23458
  snapshot(): LocalAuthorizerStats;
@@ -21954,19 +23479,29 @@ declare class LocalAuthorizer {
21954
23479
  * top of it — size the TTL to the revocation latency you can promise.
21955
23480
  */
21956
23481
  invalidate(identityId?: string): void;
21957
- /** Climb from `nodeId` and look for a grant root among its ancestors. */
21958
- private holdsAtNode;
23482
+ /** Fire the decision hooks, after the verdict and without waiting on them. */
23483
+ private announce;
23484
+ /** The node and its ancestors, from the tree this client can read. */
23485
+ private lineageOf;
23486
+ private hierarchyIncomplete;
21959
23487
  private grantRootsFor;
21960
23488
  /**
21961
- * Every page of the identity's grant roots, folded into permission → nodes.
23489
+ * Every page of the identity's grant roots, with their windows, folded
23490
+ * into permission → roots.
23491
+ *
23492
+ * Each row is one permission at one node for one assignment, so a
23493
+ * permission granted at three nodes arrives as three rows, possibly on
23494
+ * different pages. Stopping after the first page would under-report what
23495
+ * the identity holds: a false deny, the safe direction, but a wrong answer
23496
+ * all the same.
21962
23497
  *
21963
- * Each row is one permission at one node, so a permission granted at three
21964
- * nodes arrives as three rows, possibly on different pages. Stopping after
21965
- * the first page would under-report what the identity holds: a false deny,
21966
- * the safe direction, but a wrong answer all the same.
23498
+ * Rows outside their window are kept: they are what lets a denial say
23499
+ * `expired` or `not_yet_effective`, and the entry expires at the nearest
23500
+ * window boundary when that comes before the TTL, so a grant takes effect
23501
+ * or ends on time rather than up to `ttlMs` late.
21967
23502
  */
21968
23503
  private fetchGrantRoots;
21969
- private parents;
23504
+ private treeEntry;
21970
23505
  /**
21971
23506
  * Revalidate rather than re-read. The hierarchy is the expensive half and
21972
23507
  * the one that changes least, so the common case is a `304` and no transfer
@@ -22287,23 +23822,28 @@ interface CanopyTokenClaims {
22287
23822
  * The organization this session is acting in — present only on identity
22288
23823
  * tokens from an Environment with the organizations container on, for an
22289
23824
  * identity that belongs to at least one organization. Always minted
22290
- * together with `org_role`; read the pair through {@link orgContext}
23825
+ * together with `org_roles`; read the pair through {@link orgContext}
22291
23826
  * rather than separately.
22292
23827
  */
22293
23828
  org_id?: string;
22294
- /** The name of the single role the identity holds in `org_id`. */
22295
- org_role?: string;
23829
+ /**
23830
+ * The names of the roles the identity holds at the organization's own node,
23831
+ * sorted; empty for a member who holds none there. Membership is admission,
23832
+ * not a role: a member may hold roles only beneath the organization, or
23833
+ * none at all.
23834
+ */
23835
+ org_roles?: string[];
22296
23836
  [claim: string]: unknown;
22297
23837
  }
22298
23838
  /**
22299
23839
  * The organization context a verified token carries: which organization the
22300
- * session is acting in, and the one role it holds there.
23840
+ * session is acting in, and the roles it holds at that organization's node.
22301
23841
  */
22302
23842
  interface CanopyOrgContext {
22303
23843
  /** The organization's id — also a hierarchy node id, usable as `node_id`. */
22304
23844
  orgId: string;
22305
- /** The role's name (not its id): what `org_role` carries. */
22306
- orgRole: string;
23845
+ /** The roles' names (not ids) held at the organization node: what `org_roles` carries. Empty for a member holding none there. */
23846
+ orgRoles: string[];
22307
23847
  }
22308
23848
  /**
22309
23849
  * The organization context of a verified token, or `null` when it has none.
@@ -22311,16 +23851,18 @@ interface CanopyOrgContext {
22311
23851
  * `null` is an ordinary answer, not a failure: it is every token from an
22312
23852
  * Environment without the organizations container on, and every identity
22313
23853
  * that belongs to no organization yet. Branch on it rather than on the raw claims —
22314
- * Canopy mints `org_id` and `org_role` together, and this helper refuses a
23854
+ * Canopy mints `org_id` and `org_roles` together, and this helper refuses a
22315
23855
  * half-present pair instead of letting one claim be read as though the other
22316
- * were there.
23856
+ * were there. An empty `orgRoles` is a member of the organization holding no
23857
+ * role at its node; authorize such a session by evaluating, never by the
23858
+ * list's length.
22317
23859
  *
22318
23860
  * ```ts
22319
23861
  * const claims = await verifier.verify(token);
22320
23862
  * const org = orgContext(claims);
22321
23863
  *
22322
23864
  * if (org) {
22323
- * // acting inside org.orgId as org.orgRole
23865
+ * // acting inside org.orgId, holding org.orgRoles at its node
22324
23866
  * }
22325
23867
  * ```
22326
23868
  */
@@ -22432,4 +23974,4 @@ type WebhookEventData<Name extends WebhookEventName> = WebhookEvent<Name>["data"
22432
23974
  */
22433
23975
  declare function isWebhookEvent<Name extends WebhookEventName>(delivery: WebhookDelivery, name: Name): delivery is WebhookEvent<Name>;
22434
23976
 
22435
- 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 };
23977
+ export { type AccessibleNodes, 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, DEFAULT_MAX_NODES, type FailureStatus, Identities, type IdentityAssignmentItem, type IdentityItem, type IdentitySessionItem, type LocalAuthorizationQuery, LocalAuthorizer, type LocalAuthorizerOptions, type LocalAuthorizerStats, type LocalDecision, type LocalDecisionEvent, type LocalDenialReason, 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 };