Skip to main content
Tally’s grant system lets you share identity data across tenant boundaries without transferring ownership. As the subject owner, you create a grant that specifies exactly which operations the grantee tenant may perform. The grantee can then read subject data through the standard API endpoints, governed by both their membership role and the scopes you have authorized. Grants are append-only records — you revoke rather than delete them, preserving a full audit trail of who had access and when.

Create a grant

As the subject owner, call POST /v1/tenants/:tenant_id/grants. You must hold the tenant_admin role on your tenant to create grants.
curl -X POST https://api.tally.io/v1/tenants/acme-kyc/grants \
  -H "Authorization: Bearer $TALLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject_type": "entity",
    "subject_id": "ent_acme_001",
    "grantee_tenant_id": "partner-bank",
    "scopes": ["read_latest", "read_lineage"],
    "expires_at": "2027-01-01T00:00:00Z"
  }'
The 201 Created response includes the full grant record:
{
  "grant_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "subject_type": "entity",
  "subject_id": "ent_acme_001",
  "grantee_tenant_id": "partner-bank",
  "scopes": ["read_latest", "read_lineage"],
  "status": "active",
  "expires_at": "2027-01-01T00:00:00Z",
  "created_at": "2026-03-01T10:00:00Z"
}

Request body fields

FieldRequiredDescription
subject_typeYes"entity" or "individual"
subject_idYesThe subject ID you own
grantee_tenant_idYesThe tenant ID of the counterparty you want to grant access to
scopesYesNon-empty array of scope strings (see below)
expires_atNoISO 8601 datetime after which the grant is no longer valid

Grant scopes explained

Each scope controls a specific category of read operation. Grant only the scopes your counterparty actually needs.
Allows the grantee to call GET /v1/subjects/:subject_type/:subject_id to retrieve the current resolved state of the subject. This is the minimum scope for any useful integration — without it, the grantee cannot read any data about the subject.
Allows the grantee to list the full snapshot history (/history, /snapshots) and retrieve any specific snapshot by version number (/snapshots/:snapshot_version). Grant this scope when the counterparty needs to audit changes over time or reconstruct the identity at a historical point.
Allows the grantee to call GET /v1/snapshots/:snapshot_id to look up a snapshot directly by its UUID. Useful when the grantee receives a snapshot_id out-of-band (for example, in a webhook payload or a refresh request fulfillment) and needs to retrieve the corresponding envelope.
Allows the grantee to call the diff endpoints (/diff?from_version=N&to_version=M and /snapshots/:from/diff/:to) to compute a JSON Patch between two versions. Use this when the counterparty runs their own change-detection logic or needs to audit exactly what changed between versions.

List active grants

To see all grants you have issued for a subject, call GET /v1/tenants/:tenant_id/subjects/:subject_type/:subject_id/grants. You must be the subject owner.
curl https://api.tally.io/v1/tenants/acme-kyc/subjects/entity/ent_acme_001/grants \
  -H "Authorization: Bearer $TALLY_API_KEY"
{
  "items": [
    {
      "grant_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "subject_type": "entity",
      "subject_id": "ent_acme_001",
      "grantee_tenant_id": "partner-bank",
      "scopes": ["read_latest", "read_lineage"],
      "status": "active",
      "expires_at": "2027-01-01T00:00:00Z",
      "created_at": "2026-03-01T10:00:00Z"
    }
  ]
}

Revoke a grant

Call POST /v1/tenants/:tenant_id/grants/:grant_id/revoke to immediately end a counterparty’s access. Only active grants can be revoked — attempting to revoke an already-revoked or expired grant returns 409 Conflict.
curl -X POST https://api.tally.io/v1/tenants/acme-kyc/grants/f47ac10b-58cc-4372-a567-0e02b2c3d479/revoke \
  -H "Authorization: Bearer $TALLY_API_KEY"
The response returns the updated grant object with "status": "revoked":
{
  "grant_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "subject_type": "entity",
  "subject_id": "ent_acme_001",
  "grantee_tenant_id": "partner-bank",
  "scopes": ["read_latest", "read_lineage"],
  "status": "revoked",
  "expires_at": "2027-01-01T00:00:00Z",
  "created_at": "2026-03-01T10:00:00Z",
  "revoked_at": "2026-06-15T08:30:00Z"
}
Grants are append-only records in Tally. Revoking a grant sets its status to "revoked" but does not delete the underlying row. This design preserves a complete audit trail of which tenants had access to a subject and for how long. You cannot modify a grant after creation — if you need to change the scopes or expiry, revoke the existing grant and create a new one.

Accessing granted subjects (as grantee)

If another tenant has granted you access to one of their subjects, call GET /v1/tenants/:tenant_id/accessible-subjects to list all subjects you can reach via active grants.
curl "https://api.tally.io/v1/tenants/partner-bank/accessible-subjects?limit=20" \
  -H "Authorization: Bearer $TALLY_API_KEY"
{
  "items": [
    {
      "subject_type": "entity",
      "subject_id": "ent_acme_001",
      "scopes": ["read_latest", "read_lineage"],
      "expires_at": "2027-01-01T00:00:00Z",
      "access_via": "grant",
      "identity_summary": {
        "display_name": "Acme Industrial Supply, Inc."
      },
      "latest_snapshot": {
        "snapshot_id": "3f0b2c2c-2e46-4b58-8c45-3b5c58f4e9b2",
        "snapshot_version": 3,
        "generated_at": "2026-02-20T14:25:30Z"
      },
      "provenance_summary": {
        "evidence_count": 2,
        "has_attribute_paths": true,
        "has_audit": true
      }
    }
  ],
  "page": {
    "limit": 20,
    "next_cursor": null
  }
}
Pagination uses limit (default 50, max 200) and a cursor token from page.next_cursor.

Reading granted subject data

Once you have a grant, you read the subject’s data using the exact same endpoints you use for subjects you own — the tenant-scoped variants:
# Read current state (requires read_latest scope)
curl https://api.tally.io/v1/tenants/partner-bank/subjects/entity/ent_acme_001 \
  -H "Authorization: Bearer $TALLY_API_KEY"

# Read snapshot history (requires read_lineage scope)
curl https://api.tally.io/v1/tenants/partner-bank/subjects/entity/ent_acme_001/history \
  -H "Authorization: Bearer $TALLY_API_KEY"

# Read diff between two versions (requires read_diff scope)
curl "https://api.tally.io/v1/tenants/partner-bank/subjects/entity/ent_acme_001/diff?from_version=1&to_version=3" \
  -H "Authorization: Bearer $TALLY_API_KEY"
Tally checks both conditions on every request: your principal must be an active member of the grantee tenant with at least the tenant_reader role, and your tenant must hold an active grant that includes the required scope. If either check fails, the request returns 403 Forbidden.
Only one active grant per subject-grantee pair is allowed. If you try to create a second active grant for the same (subject, grantee_tenant) combination, Tally returns 409 Conflict. To change the scopes or expiry of an existing grant, first revoke it, then create a new grant with the desired settings.