Core concepts

Idempotency

Send an Idempotency-Key with a write and you can retry it as often as you like: the operation happens once, and every retry returns the original response.

Networks fail in the worst possible place — after your request arrived and before its response got back to you. Without idempotency, a retry might create a second document or send a second round of signature requests to real people. With it, a retry is free.

curl
curl -X POST https://xosign.ai/api/v1/documents \
  -H "Authorization: Bearer $XOSIGN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f9c1b7e-3d2a-4c11-9a77-6b0e2f8a1d34" \
  -d '{
    "title": "Framing Agreement",
    "recipients": [
      { "name": "Jane Contractor", "email": "jane@example.com", "channel": "email" }
    ]
  }'

How it works

  • Pick a key that is unique to the operation — a UUID per logical action is the usual choice. It can be any string up to 255 characters.
  • Send it as the Idempotency-Key header on POST /documents or POST /documents/{id}/send.
  • The first request runs normally. Any later request with the same key and the same body returns the stored original response — the same status code and the same body — without doing the work again.

Opt-in, but recommended on every write

Omitting the header is allowed and means “no deduplication”. That is fine for a one-off script; it is not what you want in production, where a timeout you did not cause can turn into a duplicate send your customer definitely notices.

What a key is bound to

A key is scoped to your account and to one endpoint, and it is bound to the exact request body. That binding is what makes replay safe: we can only promise you the original response if we know the request really was the same one.

SituationWhat happens
Same key, same body, first request still running409 idempotency_in_progress. Wait a moment and retry the identical request.
Same key, same body, first request finishedThe original response is replayed verbatim — including the original status code.
Same key, different body409 idempotency_key_reused. Use a fresh key for a different operation.
Different keyA completely new operation. Nothing is deduplicated.

Do not reuse a key across different operations

A key is not a per-session or per-customer token. Reusing one with a different body is rejected rather than silently treated as new — which is the safe outcome, but it will look like an unexplained 409 if you were recycling keys.

Errors are replayed too

If the original request failed with a client error, that failure is what gets stored and replayed. Retrying the same key will not turn a 400 into a success — fix the request and send it with a new key.

Server-side failures are the case worth retrying: document_create_failed and document_send_failed mean the write did not complete, so retrying with the same key is both safe and correct.

Sending twice is already hard to do by accident

Independently of idempotency, only a draft can be sent. A second send of an already-sent document is refused with document_not_sendable. Idempotency gives you the clean answer — the original success — instead of that error.

In practice

  • Generate the key before the first attempt and store it alongside whatever you are tracking, so a retry after a process restart still uses the same one.
  • Derive it from your own identifier — for example the id of the job that triggered the send — rather than from a timestamp or a random value you cannot reproduce.
  • Never reuse a key once its operation has succeeded.
Idempotency · XOsign API docs