> ## Documentation Index
> Fetch the complete documentation index at: https://docs.quantumapi.io/llms.txt
> Use this file to discover all available pages before exploring further.

# User roles and permissions

> The 5 system roles, the 12 resources, and the 6 actions that make up Qustody's RBAC model.

Qustody ships with five built-in **system roles** that cover the most common separation-of-duties patterns. You can also define custom roles by combining individual permissions.

RBAC is enabled by setting `CUSTODY_RBAC_ENABLED=true`. With `CUSTODY_RBAC_SEED_ON_STARTUP=true` (default), the five system roles are seeded automatically on first startup.

## System roles

| Role                 | Description                                                                       |
| -------------------- | --------------------------------------------------------------------------------- |
| `admin`              | Full access to all resources and actions                                          |
| `operator`           | Create and manage vaults, wallets, and transactions; create webhooks              |
| `viewer`             | Read-only access to vaults, wallets, transactions, policies, assets, and webhooks |
| `approver`           | Read transactions and approve or reject them                                      |
| `compliance_officer` | Read and update compliance screenings; read and export audit logs                 |

System roles are flagged `isSystem: true` and cannot be deleted.

## Permission matrix

A permission is a `resource × action` pair. There are **12 resources** and **6 actions**.

### Resources (12)

`tenants`, `vaults`, `wallets`, `transactions`, `policies`, `webhooks`, `assets`, `users`, `roles`, `credentials`, `audit`, `compliance`.

### Actions (6)

`create`, `read`, `update`, `delete`, `approve`, `export`.

### What each system role can do

| Resource       |  admin | operator | viewer | approver | compliance\_officer |
| -------------- | :----: | :------: | :----: | :------: | :-----------------: |
| `tenants`      | CRUDAE |     —    |    —   |     —    |          —          |
| `vaults`       | CRUDAE |   C R U  |    R   |     R    |          R          |
| `wallets`      | CRUDAE |    C R   |    R   |     R    |          R          |
| `transactions` | CRUDAE |    C R   |    R   |  R **A** |          R          |
| `policies`     | CRUDAE |     R    |    R   |     R    |          R          |
| `webhooks`     | CRUDAE |   C R D  |    R   |     —    |          —          |
| `assets`       | CRUDAE |     R    |    R   |     R    |          —          |
| `users`        | CRUDAE |     —    |    —   |     —    |          —          |
| `roles`        | CRUDAE |     —    |    —   |     —    |          —          |
| `credentials`  | CRUDAE |     —    |    —   |     —    |          —          |
| `audit`        | CRUDAE |     —    |    —   |     —    |       R **E**       |
| `compliance`   | CRUDAE |     —    |    —   |     —    |         R U         |

Legend: **C**=create, **R**=read, **U**=update, **D**=delete, **A**=approve, **E**=export. Empty cell means the role has no permissions for that resource.

## Assigning roles

```bash theme={null}
# Create a user
curl -X POST "$BASE_URL/v1/users" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "alice@example.com",
    "name": "Alice"
  }'

# Assign a role
curl -X POST "$BASE_URL/v1/users/{userId}/roles" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "roleId": "operator" }'

# Revoke a role
curl -X DELETE "$BASE_URL/v1/users/{userId}/roles/{roleId}" \
  -H "Authorization: Bearer $API_KEY"

# List available roles
curl "$BASE_URL/v1/roles" \
  -H "Authorization: Bearer $API_KEY"
```

A user can hold multiple roles. The effective permission set is the union of all assigned roles' permissions.

## Custom roles

You can build custom roles by composing permissions. For example, a "treasury reviewer" role that can read transactions and policies but cannot approve:

```json theme={null}
{
  "name": "treasury_reviewer",
  "description": "Read-only access to transactions and policies",
  "permissions": [
    { "resource": "transactions", "action": "read" },
    { "resource": "policies", "action": "read" },
    { "resource": "vaults", "action": "read" }
  ]
}
```

<Note>
  Custom-role management endpoints are reserved for `admin`. See the [API reference](/api-reference/introduction) for the full role-management surface.
</Note>

## SSO auto-provisioning

When SSO is enabled (`CUSTODY_SSO_ENABLED=true`) and `CUSTODY_SSO_AUTO_PROVISION=true`, users authenticated through your IdP are auto-created with the role specified by `CUSTODY_SSO_DEFAULT_ROLE` (default `viewer`).

Promote auto-provisioned users by assigning additional roles via the API.

## Best practices

<CardGroup cols={2}>
  <Card title="Restrict admin role" icon="lock">
    Assign `admin` to two or fewer humans. Use API keys with narrower permissions for service integrations.
  </Card>

  <Card title="Enforce dual control" icon="users">
    For high-value transfers, require an `operator` to create and an `approver` to approve. Use the `REQUIRE_APPROVAL` policy rule.
  </Card>

  <Card title="Audit role changes" icon="clipboard-check">
    Every role assignment and revocation is recorded in the audit log. Review periodically.
  </Card>

  <Card title="Rotate credentials" icon="rotate">
    Use `POST /v1/credentials/rotate` to rotate API keys without downtime.
  </Card>
</CardGroup>
