Help API

    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

    1. GET /v1/bookings/:uid returns the booking and an ETag header:

      ETag: "3"
      

      The number is the booking's current version. It also appears in the response body as data.version.

    2. PATCH /v1/bookings/:uid requires that ETag on If-Match:

      If-Match: "3"
      
    3. If the booking's current version is still 3, the patch applies and the version is bumped to 4. The response carries ETag: "4".

    4. If someone else mutated the booking in between (so the current version is now 4), the server returns 409 version_conflict and 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-GET the 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 — 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 — 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, or version — those return 422 field_immutable regardless 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.