Submit your first snapshot (v1)
Send aPOST request to /v1/tenants/:tenant_id/entity-states with the full envelope in the request body. For your first snapshot, set snapshot_version to 1 — Tally will reject a version greater than 1 if no prior version exists for the subject.
201 Created with the stored envelope:
Required envelope fields
| Field | Type | Description |
|---|---|---|
envelope_version | string | Must be "entity_state_envelope_v1" |
snapshot_id | UUID | A UUID you generate that uniquely identifies this snapshot |
snapshot_version | integer | 1 for the first snapshot; must be monotonically increasing |
generated_at | RFC 3339 datetime | When this snapshot was generated |
subject.subject_type | string | "entity" or "individual" |
subject.subject_id | string | Your stable identifier for the subject |
attributes | object | The identity attributes for this subject |
evidence | array | Supporting evidence records (may be an empty array) |
audit.created_by | string | The system or person that created this snapshot |
audit.created_at | RFC 3339 datetime | Creation timestamp |
audit.source | string | The data source or ingestion system |
Submit an individual snapshot
The envelope format is the same for individual subjects — only thesubject_type value and the shape of attributes differ. Individual records typically carry identity attributes such as name, date of birth, and nationalities.
Updating a snapshot (propose + apply)
Tally uses a two-step propose-and-apply workflow for incremental updates. Rather than submitting a full new snapshot, you describe the change as an RFC 6902 JSON Patch document. Tally validates the patch, derives the new snapshot ID deterministically, and creates the next version in a single atomic operation.Send a
POST to /v1/tenants/:tenant_id/entity-state-updates with the subject ID, the current snapshot as the base, and your patch operations.curl -X POST https://api.tally.io/v1/tenants/acme-kyc/entity-state-updates \
-H "Authorization: Bearer $TALLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subject_id": "ent_acme_001",
"base_snapshot_id": "3f0b2c2c-2e46-4b58-8c45-3b5c58f4e9b2",
"base_snapshot_version": 3,
"patch": [
{
"op": "test",
"path": "/attributes/relationships/0/ownership_percent",
"value": 35
},
{
"op": "replace",
"path": "/attributes/relationships/0/ownership_percent",
"value": 40
},
{
"op": "add",
"path": "/attributes/relationships/0/last_reviewed",
"value": "2026-02-20"
}
]
}'
Send a
POST to /v1/tenants/:tenant_id/entity-state-updates/:update_id/apply. Tally applies the patch to the latest snapshot, validates the result, computes a new deterministic snapshot ID, and writes the new version.curl -X POST https://api.tally.io/v1/tenants/acme-kyc/entity-state-updates/a1b2c3d4-e5f6-7890-abcd-ef1234567891/apply \
-H "Authorization: Bearer $TALLY_API_KEY"
relationship-change example: ownership in ent_acme_001 moves from 35% to 40% and a last_reviewed date is added. The test operation at the top is optional but strongly recommended — it acts as an optimistic concurrency guard that causes the apply to fail if the value has already changed.
Direct snapshot submission (v2+)
If you prefer to manage the full envelope yourself — for example when migrating records from another system — you can skip the propose/apply flow and submit a complete snapshot directly toPOST /v1/tenants/:tenant_id/entity-states with any snapshot_version value greater than 1.
snapshot_version >= 2, you must compute the complete attributes object yourself — there is no automatic merge with the previous version. Your tenant must already be the registered owner of the subject (established when you submitted version 1).