Home Features Pricing App AI Advisor Docs Compare About Training Contact Log In Get an API key
Developersv1.0.0-rc.6
Browse the guides
Developers/Working with the API

Idempotency & Concurrency

Idempotency-Key for safe retries; expected_version so two writers never silently overwrite each other.

Idempotency-Key

Use a fresh Idempotency-Key for every logical command. A key is 1–255 visible ASCII characters (! through ~), is case-sensitive, and is scoped to one integration. Shop Commander stores an encrypted replay response for seven days and reserves the key as a non-replayable tombstone for 30 days.

POST /v1/repair-orders
Idempotency-Key: fleet-wo-2026-000813
  • Same key + same operation, target, and JSON body within seven days returns the original status/body plus Idempotent-Replayed: true and Idempotency-Original-Request-Id.
  • The JSON fingerprint ignores object-key order and insignificant whitespace. Omitted and explicit null are different bodies.
  • Same key + a different operation, target, or body within 30 days returns 409 idempotency_key_reused.
  • On days 8–30, the response is no longer retained; retry returns 409 idempotency_result_expired and never executes again. After day 30 the key may be reused, but generating a new UUID-like key is safer.
  • The header is required for customer create/archive; vehicle create; appointment create/cancel/check-in/conversion; repair-order create/add-job; job actions; task create/complete; and webhook endpoint create/rotate/test.
  • It is optional but honored on customer, vehicle, appointment, task, and webhook endpoint PATCH operations. External-reference PUT/DELETE operations are naturally idempotent and also honor a supplied key.
  • Keys are scoped to your integration; two integrations can use the same key value independently.
  • If another request still owns the key, retry 409 idempotency_in_progress after the Retry-After delay. A failed/rolled-back first command does not consume the key. A committed command whose HTTP response was lost is replayed safely.

Optimistic concurrency with expected_version

Mutable resources carry version (an integer that increments on every change). Include it in updates and domain actions:

PATCH /v1/customers/cus_…
{ "expected_version": 7, "email": "jane@example.com" }

If someone — a staff member in the app, another integration — changed the record since you read it, the API responds 409 conflict / version_conflict naming the current version. Re-read, merge, and try again. Omitting expected_version is allowed and means "last write wins"; use it whenever you edit a field a human might also edit.

Ordering and duplicates in webhooks

Webhook deliveries are at-least-once and unordered. De-duplicate on the event id and treat each delivery as a signal to GET the current object rather than as the object itself — see Webhooks.

Timeouts

Requests are cut off after 60 seconds at the edge. A timed-out command may or may not have committed: retry it with the same Idempotency-Key to find out safely.