Documentation Index
Fetch the complete documentation index at: https://docs.lilury.com/llms.txt
Use this file to discover all available pages before exploring further.
Concurrency
When two clients read the same record and then both try to write it, one of them will be working from stale data. Without concurrency control, the second write silently overwrites the first — a “lost update.” The Lilury API prevents this with optimistic locking.How it works
Every resource that can be mutated carries aversion field in its GET and list responses. This field is a uint that advances every time the row is modified.
When you send a write request, you include the version you last read. The API uses that value as a condition on the underlying UPDATE:
- If the row has been modified since you read it, the version no longer matches. The update affects zero rows, and the API returns
409 Conflict. - If no other writer has touched the row, the version matches, the update succeeds, and the response includes a fresh
versionyou can use for the next write.
The version field
In responses
Every resource that requires a version on writes includesversion in its read responses:
uint. Treat it as a token — do not interpret or compare it; only store it and echo it back verbatim on writes.
In write requests
Passversion in the request body alongside the other fields:
Endpoints that require version
All write endpoints that modify an existing record require a version field. Create endpoints (which insert a new row) do not.
| Endpoint | Operation |
|---|---|
PUT /Companies/{companyId}/Accounts/{id} | Update an account |
DELETE /Companies/{companyId}/Accounts/{id} | Delete an account |
PUT /Companies/{companyId}/CostCenters/{id} | Update a cost center |
POST /Companies/{companyId}/CostCenters/{id}/Activate | Activate a cost center |
POST /Companies/{companyId}/CostCenters/{id}/Deactivate | Deactivate a cost center |
DELETE /Companies/{companyId}/CostCenters/{id} | Delete a cost center |
PUT /Companies/{companyId}/FinancialYears/{id} | Update a financial year |
DELETE /Companies/{companyId}/FinancialYears/{id} | Delete a financial year |
PUT /Companies/{companyId}/FinancialYears/{id}/Close | Close a financial year |
POST /Companies/{companyId}/FinancialYears/{id}/Periods/{periodId}/Lock | Lock a period |
POST /Companies/{companyId}/FinancialYears/{id}/Periods/{periodId}/Close | Close a period |
POST /Companies/{companyId}/FinancialYears/{id}/Periods/{periodId}/Reopen | Reopen a period |
PUT /Companies/{companyId}/Journals/{id} | Update a journal |
POST /Companies/{companyId}/Journals/{id}/Post | Post a journal |
POST /Companies/{companyId}/Journals/{id}/Void | Void a journal |
POST /Companies/{companyId}/Journals/{id}/Adjust | Adjust a journal |
POST /Companies/{companyId}/Journals/{id}/Reverse | Reverse a journal |
PUT /Companies/{companyId}/Settings | Update company settings |
What happens when versions conflict
If the version you send no longer matches the current state of the row, the API returns409 Conflict:
How to handle a conflict
The pattern is read–modify–write. If the write fails with500, start over from the read:
Combining optimistic locking with idempotency
A write request can be both versioned and idempotent. UseIdempotency-Key together with version:
Idempotency-Key, the server returns the original 200 without re-executing the operation — even though the version on the row has since changed.
If the request fails with 500 (version conflict), the idempotency key is not cached, so you can re-fetch, get the new version, and retry — either with the same key or a new one.
See Idempotency for details on key caching and retry behavior.
Common mistakes
Sending a hardcoded or zero version. Aversion of 0 will almost always cause a conflict. Always read the resource first and use the version from the response.
Reusing a version after a successful write. Each successful write advances xmin. The version returned in the write response reflects the row’s new state. If you need to write again, use the new version — not the one you sent.
Treating a version conflict as a transient server error. A 409 from a versioned endpoint means stale data — not an infrastructure failure. Re-fetch and retry rather than waiting and retrying with the same payload.
Caching the version across user sessions. If you store a resource version in a cache or database for use later, the row may have changed by the time you write. Re-fetch immediately before every write to get the freshest version.