Entity versioning¶
Many Invora entities are versioned: every committed change produces a new immutable version, while a stable key identifies the entity across all of them. This powers two things — optimistic concurrency (safe concurrent writes) and point-in-time reads (see an entity as it was).
KeyVersion¶
A versioned entity carries a composite id:
| Field | Meaning |
|---|---|
key |
The logical identifier — constant across every version of the entity. |
version |
A sequential number starting at 1, incremented on each committed change. |
versionId |
A unique identifier for this specific version. |
The first committed state is version: 1; the next is version: 2, and so on.
Optimistic concurrency (concurrencyStamp)¶
Every read of a mutable entity returns a concurrencyStamp. Pass it back on the next write (update / freeze / delete). If another write landed in between, the stamp no longer matches and the call fails with ABORTED (HTTP 409) — re-read, take the fresh stamp, and retry.
curl -X PUT https://gateway.invora.app/api/v2/documents/INV-001 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"concurrencyStamp": "a1b2c3d4",
"mask": "content.invoice.documentCurrencyCode",
"changes": { "content": { "invoice": { "documentCurrencyCode": {"value": "SAR"} } } }
}'
On a stale stamp:
{
"code": 10,
"message": "the resource was modified by another request; re-read and retry"
}
See Error handling for the retry pattern.
Point-in-time reads (timeReference)¶
List endpoints accept a timeReference on the filter to read entities as they were, rather than their current state. Its two modes are alternatives — set one or the other, not both:
referenceDate— returns each matching entity as it existed at that instant.historicalData— returns all versions over time; group byid.keyin your application to reconstruct each entity's timeline.
See List & filtering for how timeReference composes with the rest of the filter.
Reading a specific version¶
Beyond list-level time travel, versioned services let you read a single entity's history directly:
- Versioned get (
GetRequestVersioned) — fetch one specific historical version bykey+version. - Key-version query (
QueryKeyVersion) — list the version history (the sequence ofKeyVersions) for akey, so you can pick aversionto fetch.
{
"items": [
{ "key": "INV-001", "version": 1, "versionId": "3a1f..." },
{ "key": "INV-001", "version": 2, "versionId": "7c4d..." },
{ "key": "INV-001", "version": 3, "versionId": "9c8b..." }
]
}
Related¶
- List & filtering —
timeReferencewithin the list filter. - Field masks —
concurrencyStampaccompanies write masks on Update. - Error handling —
ABORTED/ 409 on a stale stamp. - Documents API — the lifecycle that produces new versions on each change.