Idempotency keys
Every POST request across every Clearvo product must include an x-idempotency-key header containing a UUID v4. This protects against duplicate submissions caused by network timeouts or retries — the example below uses POST /invoices, but the same mechanism applies to every write endpoint.
How it works
- On the first request with a given key, Clearvo processes the request and caches the response.
- On any subsequent request with the same key and identical payload, the cached response is returned immediately — nothing is re-processed or re-submitted to an authority.
- If you submit a different payload with the same key, Clearvo returns HTTP 409 Conflict. Generate a new UUID.
- Keys expire after 24 hours on Starter, 72 hours on Growth, and configurable on Enterprise.
Best practice
Use crypto.randomUUID() (Node 19+) or a UUID library. Store it alongside your pending record so you can replay it on retry.
If the request times out or you receive a 5xx, retry with the same idempotency key. You will get the cached 200 response if Clearvo already processed the request.
Each unique operation (e.g. a different invoiceNumber, or any field change) must use a fresh UUID.
async function submitWithRetry(payload, idempotencyKey) {
const MAX_RETRIES = 3;
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
try {
const res = await fetch('https://api.clearvo.io/v1/invoices', {
method: 'POST',
headers: {
'x-api-key': process.env.CLEARVO_API_KEY,
'x-idempotency-key': idempotencyKey, // same key on every retry
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (res.status === 409) throw new Error('Key reused with different payload');
if (res.ok) return res.json();
if (res.status < 500) throw new Error(`Client error: ${res.status}`);
} catch (err) {
if (attempt === MAX_RETRIES - 1) throw err;
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
}
}
}