Optimistic locking
Mutations on existing bookings use optimistic concurrency control keyed by
a monotonically-increasing version integer. The current version travels as
an ETag on reads; PATCH callers must echo it back on If-Match.
How it works
-
GET /v1/bookings/:uidreturns the booking and anETagheader:ETag: "3"The number is the booking's current
version. It also appears in the response body asdata.version. -
PATCH /v1/bookings/:uidrequires that ETag onIf-Match:If-Match: "3" -
If the booking's current version is still
3, the patch applies and the version is bumped to4. The response carriesETag: "4". -
If someone else mutated the booking in between (so the current version is now
4), the server returns409 version_conflictand your patch is not applied:{ "error": { "code": "version_conflict", "message": "The If-Match version does not match the current booking version", "details": {}, "request_id": "req_…" } }Re-
GETthe booking, apply your change on top of the fresh version, and retry.
Error matrix
| Condition | HTTP | Code |
|---|---|---|
If-Match missing | 428 Precondition Required | missing_if_match |
If-Match not a valid integer | 400 Bad Request | invalid_if_match |
| Version no longer current | 409 Conflict | version_conflict |
Weak ETags are accepted, so If-Match: W/"3" is treated the same as
If-Match: "3". The version starts at 1 on creation and increments on every
successful PATCH, cancel, or reschedule.
What about cancel and reschedule?
POST /v1/bookings/:uid/cancel and POST /v1/bookings/:uid/reschedule do
not require If-Match, since they are idempotent operations whose intent is
unambiguous regardless of intervening edits. They still bump the version, so a
later PATCH after a cancel must use the post-cancel ETag.
Example: read-modify-write
# 1) GET to learn the current version
curl -i -H "Authorization: Bearer $TOKEN" \
https://api.42min.us/v1/bookings/abc-def-…
# ETag: "3"
# { "data": { "uid": "abc-def-…", "version": 3, "metadata": { "crm_id": "C-7" }, … } }
# 2) PATCH with that ETag
curl -X PATCH https://api.42min.us/v1/bookings/abc-def-… \
-H "Authorization: Bearer $TOKEN" \
-H "If-Match: \"3\"" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"metadata":{"crm_id":"C-8","stage":"qualified"}}'
# → 200, ETag: "4"
Don'ts
- Don't try to PATCH
start,end,timezone,status,event_type_id,uid, orversion, which return422 field_immutableregardless of the ETag. To move a booking, use reschedule; to end it, use cancel. - Don't cache an ETag indefinitely. The version may bump from webhooks, workflows, or the dashboard at any moment.
- Don't try to compare ETags. They are integers, but treat them as opaque
tokens. The only safe operation is to echo them back on
If-Match.
Last updated May 14, 2026.