roles
GET /orgs/{org_id}/members/{user_id}/role
Read a member's organization role, including a custom role.
The closed v1 Membership, UserOrgMembership, Invite and SSO schemas carry only the built-in role names, so a member (or pending invite or SSO default) holding a custom role is reported there as viewer. This read returns the exact organization-wide role reference: a built-in name or the custom role_id. An unknown member returns 404.
Operation ID: getOrgMemberRole · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
org_id | path | yes | string | |
user_id | path | yes | string |
Responses
| Status | Schema | Description |
|---|---|---|
200 | RoleAssignment | The member's organization-wide role, project_id null. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
PUT /orgs/{org_id}/members/{user_id}/role
Assign exactly one organization role to an existing member.
The role is a built-in name or a custom role_id belonging to this org. Neither the new role nor the member's current role can exceed the actor's effective org permissions: an actor cannot assign, downgrade or replace a member who holds permissions it lacks. Excess permissions return 403 permission_denied with the excess in error.details. Only a built-in owner can grant or revoke owner, and the last-owner invariant is preserved. An unknown member or a custom role belonging to another org returns 404.
Operation ID: putOrgMemberRole · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
org_id | path | yes | string | |
user_id | path | yes | string |
Request body
Responses
| Status | Schema | Description |
|---|---|---|
200 | RoleAssignment | Effective organization assignment, project_id null. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
GET /orgs/{org_id}/roles
List the organization's custom roles.
Operation ID: listOrgRoles · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
org_id | path | yes | string | |
cursor | query | no | string | Opaque pagination cursor from a previous response's next_cursor. |
limit | query | no | integer | Page size (cursor pagination, 003 §1). Maximum 200. |
Pagination
Cursor pagination (003 §1): pass limit (max 200) and cursor; the
response is the pagination envelope — data plus next_cursor
(null on the last page).
Responses
| Status | Schema | Description |
|---|---|---|
200 | CustomRolePage | Custom roles owned by the resolved organization. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
POST /orgs/{org_id}/roles
Create a custom role with an explicit permission set.
Unknown permissions return 400 invalid_argument with the unknown strings in error.details. Built-in names are reserved. The target permission set must be a subset of the actor's effective org permissions; excess permissions return 403 permission_denied with those strings in details.
Operation ID: createOrgRole · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
Idempotency-Key | header | no | string | Idempotency key accepted by all POSTs (003 §1): 24 h dedup window, keyed per project. POSTs that are reads (batchSlotScores, scoreSlotEvent, deriveSlotBands, validateSourceRawPreset, sampleSource, watchEventFeedHeads and the preview operations: previewSourceMapping, previewCatalogMapping, previewLabel, previewPatternLabel, previewMarker, previewDatasetEligibility, previewSlotAudience, previewSharedCheckpointImport, previewSlotAtlasInquiry) accept the key but never replay a stored response: a retry with the same key is executed again (and metered again) against current data. A stored response that names an entity is removed when that entity is erased. A key that already answered answers only a retry of the request that stored its response: the same caller, environment, operation, path, query, scoping headers and body (a JSON body by its content, a gzip body by its inflated content). The same key with any other request is 409 already_exists with details[0].reason idempotency_key_reused, and that request is not run. The window holds no in-flight marker: two first requests sent at once can both run. A response stored by a release before this rule cannot be matched to its request and is refused the same way until it expires; send the request again with a new key. A body over 8 MiB (ingest: over its 5 MiB request limit) is run and its response is not stored. The ingest batch (POST /events) is the exception, except for an application's credentials: under a key that answered another batch it runs again, uncached, and its events' ids deduplicate them; so it does when its stored response cannot be checked. The operations that return a one-time secret store their response sealed: the stored copy opens only for the same key and credential, and one that cannot be opened is 409 idempotency_key_reused. While the server cannot check a stored response (it cannot read the key that checks it, for one), the request is 503 unavailable with Retry-After: retry with the same key. An operation whose handler claims the key itself answers the same 503, before it runs, while the key-hash pepper cannot be read; any other request sent with a key runs meanwhile, and its response is not stored. |
org_id | path | yes | string |
Idempotency
This operation accepts an Idempotency-Key header (003 §1): within
24 hours, keyed per project and caller, a retry of the same request
gets the first response, and the same key with another request is
409 already_exists (idempotency_key_reused). See the
Idempotency-Key parameter for the exceptions.
Request body
Responses
| Status | Schema | Description |
|---|---|---|
201 | CustomRole | Created custom role. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
GET /orgs/{org_id}/roles/{role_id}
Get one custom role owned by the organization.
Operation ID: getOrgRole · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
org_id | path | yes | string | |
role_id | path | yes | string |
Responses
| Status | Schema | Description |
|---|---|---|
200 | CustomRole | Custom role. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
DELETE /orgs/{org_id}/roles/{role_id}
Delete an unassigned custom role.
An assigned role returns 400 failed_precondition with org and project assignment counts in error.details. A role referenced by a SCIM default or group mapping is also in use and cannot be deleted until those references are replaced or removed. Pending invitations, SSO defaults and retained group-restoration roles also prevent deletion; error.details lists each reference count. Built-in roles cannot be deleted.
Operation ID: deleteOrgRole · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
org_id | path | yes | string | |
role_id | path | yes | string |
Responses
| Status | Schema | Description |
|---|---|---|
204 | — | Deleted custom role. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
PATCH /orgs/{org_id}/roles/{role_id}
Update a custom role.
Permissions replace the entire explicit set and take effect on the next request: authorization reads current state and caches nothing. Unknown permission strings and built-in role names return 400 invalid_argument. A role stores permission names and is evaluated against the running catalog, so a later release that adds an endpoint changes no existing grant, and a name that is no longer in the catalog grants nothing. The role's current set and the resulting set must both be subsets of the actor's effective org permissions (an actor cannot edit a role that grants permissions it lacks); excess permissions return 403 permission_denied with the excess in error.details. Omitting permissions preserves the existing set; empty sets and wildcard permissions are invalid.
Operation ID: updateOrgRole · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
org_id | path | yes | string | |
role_id | path | yes | string |
Request body
Responses
| Status | Schema | Description |
|---|---|---|
200 | CustomRole | Updated custom role. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
GET /orgs/{org_id}/roles/{role_id}/purposes
Get a custom role's purpose allow-list.
The custom role's purpose allow-list (WP-V12 req 8; WP-A5 evaluator extension). purposes: null means unrestricted, the default. Built-in roles are always unrestricted and have no allow-list. Additive to the closed CustomRole record. Requires org role admin or above. Console sessions only.
Operation ID: getOrgRolePurposes · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
org_id | path | yes | string | |
role_id | path | yes | string |
Responses
| Status | Schema | Description |
|---|---|---|
200 | PrincipalPurposes | The role's purpose allow-list. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
PUT /orgs/{org_id}/roles/{role_id}/purposes
Replace a custom role's purpose allow-list.
Replaces the role's allow-list (WP-V12 req 8): null lifts the restriction; a list names 1–16 unique purpose names. The role is organization-wide, so names are checked for syntax only (malformed names and unknown fields are 400 invalid_argument); a name a project has not registered allows nothing there. Members holding the role then get 403 permission_denied (details[0].reason purpose_not_allowed, details[0].purpose) on every output path whose effective purpose is outside the list; a built-in role never restricts. The listed purposes pin every project registry of the organization (purpose_referenced). The change and its role.purposes.update audit record commit in one transaction; an unchanged list writes nothing. Takes effect within 5 seconds (serving outputs cache a session's allow-list for up to 5 seconds). Requires org role admin or above. Console sessions only.
Operation ID: putOrgRolePurposes · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
org_id | path | yes | string | |
role_id | path | yes | string |
Request body
Responses
| Status | Schema | Description |
|---|---|---|
200 | PrincipalPurposes | The stored allow-list. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
GET /projects/{project_id}/members/{user_id}/role
Read a member's project role override.
Resolve the project's org before authorizing. Returns the override that replaces the member's org role for project-scoped operations; 404 when the member has no override on this project (the org role applies).
Operation ID: getProjectMemberRole · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
project_id | path | yes | string | |
user_id | path | yes | string |
Responses
| Status | Schema | Description |
|---|---|---|
200 | RoleAssignment | The project override, project_id is the addressed project. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
PUT /projects/{project_id}/members/{user_id}/role
Replace the member's project role override.
Resolve the project's org before authorizing. A member must belong to that org; custom role IDs must belong to the same org. The override replaces the org role for project-scoped operations and never changes the org role for org-scoped operations. The new role, and the member's current role in the project (an existing override, else the org role), must both be subsets of the actor's effective org permissions; excess permissions return 403 permission_denied. Owner management remains restricted to built-in owner sessions.
Operation ID: putProjectMemberRole · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
project_id | path | yes | string | |
user_id | path | yes | string |
Request body
Responses
| Status | Schema | Description |
|---|---|---|
200 | RoleAssignment | Saved project override, project_id is the addressed project. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
DELETE /projects/{project_id}/members/{user_id}/role
Remove a project role override and restore org-role inheritance.
Removing an override may increase permissions. The resulting inherited org permission set, and the override being removed, must both be subsets of the actor's effective org permissions; owner management restrictions still apply.
Operation ID: deleteProjectMemberRole · Service: gateway-api
Authentication
consoleSession(http (bearer)) — Console session (003 §2): Identity Platform JWT. Data-plane calls addX-Tessera-Project+X-Tessera-Environmentheaders, validated against org membership.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
project_id | path | yes | string | |
user_id | path | yes | string |
Responses
| Status | Schema | Description |
|---|---|---|
204 | — | Override removed; the member now inherits the org role. |
default | ErrorEnvelope | Error response (003 §1). Every non-2xx response uses this envelope; the HTTP status matches error.code. Rate-limited requests get 429 resource_exhausted with retry_after_seconds and a Retry-After header; the X-RateLimit-* headers ride on EVERY response, success or error (003 §1; plan-driven per API key + endpoint class — WP-B2). A 503 unavailable carries retry_after_seconds too for a lock-wait timeout (SQLSTATE 55P03), a rule preview at capacity (preview_capacity_exhausted), or a label preview during which the erasure of every entity holding its censor clock began (label_preview_clock_entity_erased): how long to wait before retrying. |
Errors
Every non-2xx response uses the 003 §1 error envelope; error.request_id
matches the X-Request-Id response header, and the HTTP status always
matches error.code:
{
"error": {
"code": "invalid_argument",
"details": [
{
"type": "field_violation"
}
],
"message": "human-readable",
"request_id": "req_01hxample"
}
}
Closed error-code set (003 §1): invalid_argument, unauthenticated, permission_denied, not_found, already_exists, failed_precondition, resource_exhausted, internal, unavailable.
resource_exhausted responses (HTTP 429) additionally carry
retry_after_seconds. See ErrorEnvelope.