Skip to main content
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

RoleDescription
adminFull access to all resources and actions
operatorCreate and manage vaults, wallets, and transactions; create webhooks
viewerRead-only access to vaults, wallets, transactions, policies, assets, and webhooks
approverRead transactions and approve or reject them
compliance_officerRead 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

Resourceadminoperatorviewerapprovercompliance_officer
tenantsCRUDAE
vaultsCRUDAEC R URRR
walletsCRUDAEC RRRR
transactionsCRUDAEC RRR AR
policiesCRUDAERRRR
webhooksCRUDAEC R DR
assetsCRUDAERRR
usersCRUDAE
rolesCRUDAE
credentialsCRUDAE
auditCRUDAER E
complianceCRUDAER 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

# 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:
{
  "name": "treasury_reviewer",
  "description": "Read-only access to transactions and policies",
  "permissions": [
    { "resource": "transactions", "action": "read" },
    { "resource": "policies", "action": "read" },
    { "resource": "vaults", "action": "read" }
  ]
}
Custom-role management endpoints are reserved for admin. See the API reference for the full role-management surface.

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

Restrict admin role

Assign admin to two or fewer humans. Use API keys with narrower permissions for service integrations.

Enforce dual control

For high-value transfers, require an operator to create and an approver to approve. Use the REQUIRE_APPROVAL policy rule.

Audit role changes

Every role assignment and revocation is recorded in the audit log. Review periodically.

Rotate credentials

Use POST /v1/credentials/rotate to rotate API keys without downtime.