Propose an update
POST /v1/tenants/:tenant_id/entity-state-updates
Submits a patch proposal against a specific snapshot of a subject. The server validates the patch operations and records the proposal with status proposed. No data is changed yet.
Requires at least the tenant_proposer role in the target tenant, and your tenant must be the subject owner.
Path parameters
The ID of the tenant that owns the subject.
Body parameters
The identifier of the subject to update.
The kind of subject. Must be
entity or individual.The
snapshot_id of the current snapshot you are patching from. This acts as
an optimistic lock — if another update has been applied since you read this
snapshot, the subsequent /apply call will return 409 Conflict.The version number of the base snapshot. Must be an integer ≥ 1.
An array of RFC 6902 patch
operations to apply. Each operation is an object with the following fields:
An optional client-supplied idempotency key. Submitting the same
request_id twice returns the original update_id without creating a
duplicate record.An optional free-form string identifying who initiated the proposal, for
audit purposes.
Response
201 Created
update_id — you’ll need it to apply the update.
Example request
Apply an update
POST /v1/tenants/:tenant_id/entity-state-updates/:update_id/apply
Applies a previously proposed update. The server re-validates that the base snapshot is still the latest for this subject, executes the patch operations, validates the resulting envelope, and writes a new immutable snapshot. This entire operation runs inside a serializable database transaction.
Requires at least the tenant_editor role in the target tenant, and your tenant must be the subject owner.
Path parameters
The ID of the tenant that owns the subject.
The
update_id returned by the propose step.Request body
No request body is needed.Response
201 Created — the full snapshot envelope for the newly written snapshot.
Error responses
| Status | Code | Meaning |
|---|---|---|
404 | not_found | No update exists with the given update_id. |
409 | conflict | The update has already been applied, is not in proposed status, or the base snapshot is no longer the latest for this subject (stale base — re-propose). |
How the new snapshot_id is derived
The new snapshot_id is deterministic — given the same inputs you will always get the same output:
snapshot_id client-side before the apply call completes, and it provides a natural deduplication guarantee: re-applying the exact same patch to the same base snapshot is idempotent at the storage level.
Full curl sequence
Optimistic concurrency lock. The
base_snapshot_id you supply at propose time must still be the current latest snapshot when you call /apply. If another update is applied to this subject between your propose and apply calls, the apply will return 409 Conflict with the message "Base snapshot is stale." You’ll need to re-read the subject’s latest snapshot and re-propose your changes on top of it. This prevents silent last-write-wins overwriting in multi-writer environments.