---
title: User Roles | Developer Documentation
description: Provision organization members with roles (including the read-only ViewerV2 role) over the API in a self-hosted LlamaCloud deployment.
---

## Self-Hosting Documentation Access

This section requires a password to access. Interested in self-hosting? [Contact sales](https://www.llamaindex.ai/contact) to learn more.

Password:

Access Documentation

Self-Hosting Documentation Access Granted Logout

Each organization member in your LlamaCloud deployment holds a role that controls what they can do:

- **`Admin`** — full access to the organization and its projects.
- **`ViewerV2`** (shown as “Viewer” in the UI) — read-only. Viewers can browse projects and resources and read job results, but requests that create or modify anything are rejected with a `403`.

The role named `Viewer` is an older role that still permits some write operations — don’t use it for read-only members; use `ViewerV2`.

The `IS_VIEWER_V2_ROLE_ENABLED` feature flag (on by default) controls whether `ViewerV2` appears in the roles listing below. It gates discovery only: roles already assigned keep working, and the read-only enforcement itself is unconditional. If your deployment disables the flag, re-enable it before provisioning read-only members.

## Provision members with a role over the API

Managing members over the API requires an API key belonging to an organization admin. Set up your environment first:

Terminal window

```
export LLAMA_CLOUD_API_KEY="<org-admin-api-key>"
export HOST="https://<your-llamacloud-host>"
export ORG_ID="<your-organization-id>"   # shown on the Organization Settings page
```

### Look up the role ID

Role IDs are generated per deployment, so look the role up by name rather than hardcoding an ID. The ID is stable within a deployment, so this is a one-time lookup:

Terminal window

```
export ROLE_ID=$(curl -s "$HOST/api/v1/organizations/$ORG_ID/roles" \
  -H "Authorization: Bearer $LLAMA_CLOUD_API_KEY" \
  | jq -r '.[] | select(.name=="ViewerV2") | .id')
```

### Add members

The request body is an array, so add several members in one call. Member additions are rate-limited per organization, so prefer one batched request over calling in a loop. `project_ids` controls scope: `null` grants access across the whole organization, while a list of project IDs restricts the member to those projects:

Terminal window

```
curl -X PUT "$HOST/api/v1/organizations/$ORG_ID/users" \
  -H "Authorization: Bearer $LLAMA_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[{ "email": "person@example.com", "project_ids": null, "role_id": "'"$ROLE_ID"'" }]'
```

Adding by email works before the person has signed up: the invite is stored and redeemed automatically when they sign up with that email address. Responses to email-based additions always list the member as `pending`.

### Remove a member

Remove a member by email or by user ID:

Terminal window

```
curl -X DELETE "$HOST/api/v1/organizations/$ORG_ID/users/person@example.com" \
  -H "Authorization: Bearer $LLAMA_CLOUD_API_KEY"
```
