@shmaplex/xplant-sdk 0.7.0 is out: what's new →
xPlantAPI

Idempotency

Send an Idempotency-Key on a write so retrying it after a timeout can't create a duplicate.

A network can fail after the server has done the work but before you get the answer. Retrying then risks doing the work twice: two tasks, two scans, two runs started. An Idempotency-Key header makes the retry safe.

curl -X POST https://app.xplantpro.com/api/v1/tasks \
  -H "Authorization: Bearer $XPLANT_API_KEY" \
  -H "Idempotency-Key: bench-3-0f2a7c91" \
  -H "Content-Type: application/json" \
  -d '{"title": "Check jar 47"}'

A repeat with the same key returns the first response, with the same status and body, and the response header Idempotent-Replay: true. The write happens once.

Which endpoints honour it

The header is honoured on these endpoints, and only these:

Everywhere else the header is ignored. Sensor readings and device events make retries safe with your own external_id instead (plus recorded_at for readings): a repeat of one already stored for the same device is skipped, and a single repeat answers 201 with the stored record and meta.duplicate: true.

The rules

Format8–255 characters from A–Z a–z 0–9 . _ : ~ -. A malformed key answers 422 VALIDATION_ERROR rather than being silently ignored.
ScopeYour key plus the endpoint. The same string on two endpoints is two different writes, and two keys never collide.
How long24 hours. After that, the same key starts a fresh write.
Still runningIf the first request hasn't finished, a repeat answers 409 IDEMPOTENCY_IN_FLIGHT with Retry-After: 1. Wait and send it again; don't assume it failed.
Failed writesAren't replayed. If the first attempt failed, the next attempt runs for real, so a passing glitch isn't pinned to your key for a day.
No headerThe write runs unprotected. Idempotency is opt-in.

Choosing keys

Make one key per intent, not per attempt. Every retry of the same logical write sends the same value; a new write sends a new one.

Good keys come from your own data: station-3-run-wk38-start, scanner-3-<scan uuid>, nightly-sync-2026-09-25-task-8812. A random UUID generated once, stored with the pending write and reused on each retry, also works.

The JavaScript SDK takes { idempotencyKey } as the last argument of any write, and with retry: true it generates a key for you and reuses it across its own retries.

Edit on GitHub

On this page