Tally is a multi-tenant platform. Every piece of data you write — subjects, snapshots, evidence, grants — lives inside a tenant. Tenants are fully isolated from one another: one tenant cannot read another’s data unless the owning tenant has explicitly issued a grant. Within a tenant, you control access with a five-level role system that separates read access, write access, and administrative operations cleanly.
Tenants
A tenant is a named, isolated workspace in Tally identified by a tenant_id you choose at creation time.
curl -X POST https://api.tally.so/v1/tenants \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "acme-kyc",
"name": "Acme KYC Team"
}'
{
"tenant_id": "acme-kyc",
"name": "Acme KYC Team",
"created_at": "2026-03-01T10:00:00Z"
}
Every resource in Tally is scoped to a tenant:
- Subjects are owned by the tenant that submitted their first snapshot
- Snapshots are written and read through tenant-scoped endpoints
- Grants are issued by owning tenants to grantee tenants
- Members are principals (OIDC identities) who have a role within the tenant
tenant_id values are immutable after creation. Choose a stable,
human-readable slug — for example, your organization name or business unit —
because it will appear in every API path you use.
Membership roles
Tally uses five roles, ordered from least to most privilege. Higher roles include all capabilities of lower roles.
| Role | Capabilities |
|---|
tenant_reader | Read owned subjects, accessible subjects (via grants), grants list, webhooks |
tenant_proposer | All reader capabilities, plus: propose state updates (creates a pending update record for editor review) |
tenant_editor | All proposer capabilities, plus: apply proposed updates, create new entity state snapshots |
tenant_admin | All editor capabilities, plus: manage members (add/update roles), create and revoke grants |
tenant_owner | Full control including tenant configuration and accountability transfer |
For automated service accounts that only write snapshots, grant
tenant_editor. For read-only integrations or downstream consumers who
receive grants, tenant_reader is sufficient.
Adding members
Add or update a member’s role with:
PUT /v1/tenants/:tenant_id/members/:principal_id
The principal_id must be an OIDC principal in the format oidc:{issuer}#{sub}, where {issuer} is your OIDC issuer URL and {sub} is the user’s subject claim from the ID token.
curl -X PUT \
"https://api.tally.so/v1/tenants/acme-kyc/members/oidc:https%3A%2F%2Fauth.acme.com%23usr_42" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"role": "tenant_editor"
}'
{
"tenant_id": "acme-kyc",
"principal_id": "oidc:https://auth.acme.com#usr_42",
"role": "tenant_editor",
"status": "active",
"updated_at": "2026-03-01T11:00:00Z"
}
You can call this endpoint again with a different role to change an existing member’s access level. The role update takes effect immediately. This endpoint requires at least tenant_admin on the tenant.
Only a tenant_admin or tenant_owner can add or update members. Make
sure at least one human principal holds tenant_owner in every tenant so
you are never locked out of administrative operations.
Subject ownership
The tenant that writes the first snapshot (snapshot_version: 1) for a subject automatically and permanently becomes that subject’s owner. Ownership is structural — it is established once and never transferred.
Only the owning tenant can write new snapshots for a subject. If you attempt to write a snapshot for a subject owned by a different tenant, Tally returns 403 Forbidden.
To inspect which tenant owns a subject:
curl "https://api.tally.so/v1/tenants/acme-kyc/subjects/entity/ent_acme_001/owners" \
-H "Authorization: Bearer <token>"
{
"items": [
{
"tenant_id": "acme-kyc",
"name": "Acme KYC Team",
"owner_since": "2026-02-18T09:00:00Z"
}
]
}
This endpoint is available to any member with at least tenant_reader on the tenant in the path parameter.
Usage tracking
Tenant admins can view snapshot write counts for any time window via the usage endpoint:
curl "https://api.tally.so/v1/tenants/acme-kyc/usage?from=2026-02-01T00:00:00Z&to=2026-02-29T23:59:59Z" \
-H "Authorization: Bearer <token>"
{
"tenant_id": "acme-kyc",
"window": {
"from": "2026-02-01T00:00:00.000Z",
"to": "2026-02-29T23:59:59.000Z"
},
"usage": {
"snapshots_written": 142
}
}
If you omit from and to, the window defaults to the last 30 days (from 29 days ago UTC midnight through now). You must provide both from and to together — providing only one returns a 400 Bad Request. Both values must be valid ISO 8601 datetimes, and from must be less than or equal to to.
This endpoint requires at least tenant_admin on the tenant.