Available on Enterprise plans. An organization without an Enterprise plan is refused with HTTP
402 and the error code
enterprise_plan_required. Self-hosted deployments need an Enterprise
license for the same endpoints. To enable it, reach out to
enterprise@langwatch.ai.Intro
A grant is one sentence: this principal holds this role, here. A role is what you may do; a grant is who holds it, and where. The Grants API succeeds the Role Bindings API and reads and writes the same records, so a binding made through either one shows up in both. For the concepts behind it, including who may grant what, read Roles & access.Authentication
Requires an organization-level API key withorganization:manage. Pass it as a Bearer token:
Endpoints
The grant
Creating a grant
expiresAt is optional; when given, it must be in the future (422 grant_expiry_in_past).
Each create makes its own grant with its own id, even when the same principal already holds the same role at the same scope. To make a create safe to retry, send an Idempotency-Key header: a repeat with the same key and the same body answers with the grant the first call made and does not create a second. The same key with a different body is refused with 409 idempotency_error.
An organization holds at most 10,000 grants. One more is refused with 409 grant_limit_reached, and the limit is in meta.limit.
Changing and revoking
PATCH takes only { "roleId": "..." }. The principal and the scope are the grant’s identity; to move a grant, revoke it and create another. DELETE answers { "id": "grant_abc123", "revoked": true }.
The last live administrator grant on the organization cannot be revoked or lowered: the refusals are 400 cannot_remove_last_admin and cannot_demote_last_admin.
Listing
GET /api/v1/grants filters on principalType with principalId, roleId, scopeType, scopeId and status. An omitted status lists both active and expired grants.
Pages are cursor based. limit defaults to 50 and cannot exceed 200. Every page but the last carries nextCursor; pass it back as cursor for the next page. The last page carries null. A cursor the API did not hand out is refused as invalid.
You cannot grant more than you hold
You cannot grant a role carrying a permission you do not hold yourself at that scope. The check applies to every principal, yourself included, and to changing a grant’s role as well as creating one. It is the same rule on this API, on the Role Bindings API and in the product. The caller is checked as itself. A request made with an API key is judged by that key’s own permissions, never by those of the person who owns it. An expired grant does not count towards what the caller holds. The refusal is 403grant_exceeds_caller_permissions, and it names what you lack: