Access grants
An access grant gives a user one access point: the tenant, a client, a party, an entity, a cash account or a custody account. The user sees the access point and everything below it; what the user may do there comes from the user's groups. A grant has no role of its own. An admin sees everything and gets no grants. A lens is no access point: you share it on the lens with PUT /v1/lenses/{id}/shares.
The grant
idstringStable identifier. A UUID.
user_idstringThe user the grant is for.
subject_kindstringtenant,client,party,entity,cash_accountorcustody_account.subject_idstring or nullThe access point.
nullfor the tenant.statusstringactive,expiredorrevoked.originstringv1orlegacy.granted_atstringWhen the grant was made.
granted_by_user_id, expires_atstring or nullWho made the grant, and until when it holds.
expires_atisnullwithout an expiry.revoked_at, revoked_by_user_id, revoked_reasonstring or nullSet once the grant is revoked. A revoked grant stays readable.
user_rolestring or nullThe user's role:
adminoruser.nullwhen the person is no longer a member of the tenant.group_idsstring[]The groups the user is in now.
List grants
Needs access:read. An admin gets every grant; anyone else gets their own. Pages in id order. Grants of Aleta staff and API keys are left out, as in GET /v1/users.
user_id, subject_kind, subject_idstringFilters.
user_idandsubject_idmust be UUIDs andsubject_kindone of the six kinds above; anything else is a400.include_inactivebooleanRevoked and expired grants too (the audit view). Default
false.limit, cursorinteger, stringPage size (default 100, at most 1 000) and the previous page's
next_cursor.
{
"data": [
{
"id": "019e9b20-4c1d-7a2e-9f30-1b2c3d4e5f60",
"user_id": "019e9a40-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
"subject_kind": "custody_account",
"subject_id": "019dfed3-16d5-7b8c-878c-aca5a2407b9e",
"status": "active",
"origin": "v1",
"granted_at": "2026-10-17T09:00:00.000000Z",
"granted_by_user_id": "019e9a40-0000-7000-8000-000000000001",
"expires_at": null,
"revoked_at": null,
"revoked_by_user_id": null,
"revoked_reason": null,
"user_role": "user",
"group_ids": ["019e9a11-2b6c-7d3e-8f10-6a2b3c4d5e6f"]
}
],
"next_cursor": null,
"limit": 100
}
Get a grant
One grant, also a revoked or expired one. 404 for a grant you may not see.
Grant access
Only an admin grants access: a person, or an API key an admin owns (Aleta's fleet key too); the token needs access:write. 201 with the new grant, 200 with the active grant the user already holds on the access point. Takes ?dry_run=true and Idempotency-Key (see Writes) and is logged once.
user_idstringA user of the tenant.
400for an admin, Aleta staff, an API key or anyone not in the tenant.subject_kindstringOne of the six kinds.
400forlens.subject_idstringLeft out for the tenant.
404when the access point does not exist or you cannot see it.expires_atstringOptional:
YYYY-MM-DDor an RFC 3339 timestamp in the future.
Unknown fields are a 400, role and include_sub_clients too. A second grant on the same access point with another expires_at is a 409 conflict; revoke the first.
curl -X POST https://api.aleta.ai/v1/access-grants \
-H "Authorization: Bearer {access_token}" \
-H "Idempotency-Key: {uuid}" \
-H "Content-Type: application/json" \
-d '{"user_id": "019e9a40-1a2b-7c3d-8e4f-5a6b7c8d9e0f", "subject_kind": "custody_account", "subject_id": "019dfed3-16d5-7b8c-878c-aca5a2407b9e"}'
Revoke a grant
Only an admin; the token needs access:write. 204, also for a grant that is revoked already. ?reason= is kept as revoked_reason; without it the reason is revoked via api-public. Takes ?dry_run=true and Idempotency-Key. The grant stays readable. 404 for a grant you may not see, a grant of Aleta staff or an API key (which the list leaves out) included, 409 legacy_managed for a grant from the legacy platform before your move.