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

# Principals & Roles

> How the two-layer access model governs what principals can do within a tenant.

Access in Tally Platform is controlled by two independent role dimensions on each principal's membership record. Both must be present for a principal to act within a tenant.

## Two-layer role model

### Account roles (`tenancy_role`)

Account roles govern tenant administration — adding and removing members, managing billing. They say nothing about what a principal can do with subjects or grants.

| Role             | What it allows                                                                                           |
| ---------------- | -------------------------------------------------------------------------------------------------------- |
| `account_admin`  | Manage all principal access records. At least one active `account_admin` must always remain on a tenant. |
| `billing_admin`  | Manage billing and subscription details.                                                                 |
| `account_viewer` | Read tenant membership and billing information.                                                          |

Account roles are independent capabilities, not a ranked hierarchy.

### Data-access roles (`api_functional_role`)

Data-access roles control what a principal can do with subjects belonging to (or accessible via grants held by) their own tenant. These form a **ranked hierarchy** — a higher rank includes all permissions of lower ranks.

| Role              | Rank | What it allows                                                                                                                            |
| ----------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `tenant_owner`    | 5    | Permanent accountability anchor for the tenant's subjects. Can do everything `tenant_admin` can. May only be held by a `human` principal. |
| `tenant_admin`    | 4    | Full subject read/write, grant management, refresh requests.                                                                              |
| `tenant_editor`   | 3    | Create and apply updates; read all subject data.                                                                                          |
| `tenant_proposer` | 2    | Propose updates; read all subject data.                                                                                                   |
| `tenant_reader`   | 1    | Read subject data only. Minimum role for counterparty access.                                                                             |

A principal may hold both a `tenancy_role` and an `api_functional_role` simultaneously, or just one, depending on their responsibilities.

## The `tenant_owner` role

`tenant_owner` is the accountability anchor for the Tenant↔Subject relationship. It is not simply a higher-privilege version of `tenant_admin` — it carries legal and compliance significance and may only be held by a `human` principal.

Ownership of a subject (the Tenant↔Subject pairing) is permanent and structural. What transfers via the [ownership transfer offer](/api-reference/transfer-offers/create) flow is the `tenant_owner` *role* within the owning tenant — not the subject itself.

## Counterparty access (`allow_counterparty_access`)

Grants operate at the tenant level, but accessing counterparty subjects also requires a per-principal flag. A principal with `allow_counterparty_access: false` (the default) receives `403` on counterparty endpoints even if their tenant holds active grants.

The flag is set by an `account_admin` and may only be enabled by a **human** caller. See [Access Grants](/concepts/grants) for the full workflow.

## Setting roles

All role and flag management goes through `PUT /v1/tenants/{tenant_id}/principals/{principal_id}`. The endpoint uses PATCH semantics — omitted fields are unchanged.

```bash theme={null}
# Add a service account with read-only data access
curl -X PUT https://tally-platform-api-iikaevm4pq-ue.a.run.app/v1/tenants/{tenant_id}/principals/{principal_id} \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "api_functional_role": "tenant_reader",
    "principal_type": "service_account"
  }'

# Grant counterparty read access to a human analyst (must be called by a human account_admin)
curl -X PUT https://tally-platform-api-iikaevm4pq-ue.a.run.app/v1/tenants/{tenant_id}/principals/{principal_id} \
  -H "Authorization: Bearer $HUMAN_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "allow_counterparty_access": true }'
```

See [Authentication](/authentication) for details on `principal_type` and human-only constraints.
