version that bumps on every modification. The API
surfaces it as an ETag header; writes that modify the resource must
include If-Match with the last-seen ETag. Mismatch = 409 Conflict
with the current resource.
Read → ETag
"version": 5 — same value, two surfaces.
Write → If-Match
| Server state | Header | Result |
|---|---|---|
version=5 | If-Match: "5" | 200 OK, version bumps to 6 |
version=7 (someone edited) | If-Match: "5" | 409 Conflict with current resource in body |
No If-Match header | — | 400 Bad Request — header required on versioned resources |
Conflict resolution
409 responses carry the full current resource in the body. You don’t
need a separate GET to reconcile.
Which resources are versioned
Any resource that NT24 staff can also edit in the web app:- Buyer (
TradePartner) - Order
- Invoice (sub-resource on order)
- Payment (sub-resource on order)
- Transport (pickup/delivery milestones are append-only; see note)
Transport milestones — immutable once set
Pickup and delivery confirmations are not optimistically concurrent. They are immutable once set:POST /transport/pickuptwice → second call returns409withmilestone-already-setproblem type.- To reverse, use the explicit
POST /transport/pickup/revokeendpoint. - Same for
delivery.
Under the hood
Versions are backed by Hibernate’s@Version column — platform-wide on
all audited entities. Envers captures every revision for audit trail
(who/when); @Version prevents concurrent overwrites at commit time.
Next
Error reference
409 version-mismatch detail.Idempotency
Safe retries on writes.