Idempotency
A network can fail after Essentio did what you asked but before your program heard the answer. Send an Idempotency-Key with every create and every Action, and a retry with the same key is answered with the first request’s answer instead of creating a second Client, sending a document twice or recording a Payment twice.
Sending a key
The key is a header: any string of 1 to 255 printable characters with no space that names this one request — a UUID, or your own order or job id. Make it before the first attempt and keep it for every retry of that request.
A create that may be retried
curl https://api.essentio.pro/v1/clients \
-H "Authorization: Bearer $ESSENTIO_API_KEY" \
-H "Idempotency-Key: order-10427" \
-H "Content-Type: application/json" \
-d '{"name": "Northwind Studio", "email": "accounts@northwind.example", "country": "CY"}'
What a key does
A key names one request: the operation its method and path reach, with the ids in its path, its query and its body. The body is compared as data: a JSON body by its values, so the same fields in another order are the same request; a form-encoded body by its field names and values, in any order. A body that is neither — or is sent as JSON and does not parse — is compared by its exact bytes, so it is never the same request as an empty body or another such body.
- The same key and the same request within 24 hours: the answer is the first request’s, byte for byte, with the header
Idempotent-Replayed: true. Nothing is done again. - The same key with another request: refused with a
422of typeidempotency. Nothing is done. Use a new key for a new request. - A request that was refused or failed keeps no key: only a
2xxanswer is kept. Correct the request and send it again under the same key. - The same request while the first is still being performed: answered
409of typeidempotency_in_flightat once, and nothing is done. Send it again in a few seconds to read the first one’s answer. - A request that died on Essentio’s side before it answered holds its key for at most five minutes; after that the same key is performed again.
A key belongs to the credential that sent it — an API key, or a Connected app: another key of the same Business never meets it. After 24 hours it is forgotten, and the same key starts a new request. A Test business’s reset forgets them all.
A retry of a create that succeeded
HTTP/2 201
Content-Type: application/json
Idempotent-Replayed: true
The operations that take one
Every create and every Action takes an Idempotency-Key:
POST /v1/clients— Create a ClientPOST /v1/documents— Create a DraftPOST /v1/documents/{document}/issue— Issue a DraftPOST /v1/documents/{document}/send— Send a documentPOST /v1/documents/{document}/cancel— Cancel a documentPOST /v1/documents/{document}/convert— Convert a Proforma InvoicePOST /v1/documents/{document}/payments— Record a PaymentPOST /v1/payments/{payment}/reverse— Reverse a PaymentPOST /v1/products— Create a Product
An update (PATCH) and a delete need none: sent twice, they set the same values again, or find nothing left to delete. An Action sent twice without a key is refused by what the first one did — the document is already issued or cancelled — but a Send sent twice without a key sends twice, and a Payment recorded twice is two Payments: send those with a key.
Retrying with a key
Retry a request whose answer was lost — a timeout or a dropped connection — or that was answered 409 or 5xx, with the same key and the same body. A 429 is retried after Retry-After seconds (Rate limits); any other 4xx would be answered the same, so correct the request first.
Create a Client, retrying safely
key=$(uuidgen)
for attempt in 1 2 3; do
status=$(curl -s -D headers.txt -o client.json -w '%{http_code}' https://api.essentio.pro/v1/clients \
-H "Authorization: Bearer $ESSENTIO_API_KEY" \
-H "Idempotency-Key: $key" \
-H "Content-Type: application/json" \
-d '{"name": "Northwind Studio", "email": "accounts@northwind.example", "country": "CY"}' || true)
case "$status" in
000|409|5??) sleep $((attempt * 2)) ;; # lost, in flight or failed: the same key again
*) break ;;
esac
done
[ "$status" = 000 ] && { echo "Essentio could not be reached: try again later with the same key"; exit 1; }
echo "$status $(jq -r '.id // .error.message' client.json)" \
"$(grep -qi '^Idempotent-Replayed: true' headers.txt && echo '(replayed)')"
An AI assistant’s tools take the same key as an idempotency_key argument.