Errors, retries and idempotency
Error envelope
Assayra errors use a stable JSON shape:
{
"error": "validation_failed",
"message": "The request did not satisfy the API contract.",
"details": {
"field": "workflowId"
}
}
Never expose internal details directly to an applicant. Map known codes to your product language and retain the request correlation in protected logs.
Status codes
| HTTP | Meaning | Recommended handling |
|---|---|---|
400 | Invalid syntax, schema or unsupported state | Correct the request; do not retry unchanged |
401 | Missing or invalid credential | Stop, refresh configuration and alert if unexpected |
403 | Scope, role, entitlement or state denied | Do not retry until authorization changes |
404 | Route/record unavailable | Check environment and tenant context |
409 | State conflict or conflicting idempotency reuse | Reconcile the original result before creating a new key |
429 | Rate limit exceeded | Back off with jitter and respect Retry-After when present |
5xx | Temporary server-side failure | Retry boundedly with the same idempotency key |
Idempotency keys
Authenticated mutations require Idempotency-Key in production. Use a cryptographically random value unique to the intended business operation.
Idempotency-Key: 018f65c6-7ee2-7a84-9f3c-3ee29a70dc8b
The same key and same payload return the original response. Reusing the key with a different payload is rejected. Keep the key until the network outcome is known.
const idempotencyKey = crypto.randomUUID();
await proofline.applications.create(input, { idempotencyKey });
// A network retry must reuse idempotencyKey—not generate another one.
Retry policy
Use exponential backoff with jitter, a bounded attempt count, and a final reconciliation read:
const delays = [250, 750, 2000, 5000];
for (let attempt = 0; attempt <= delays.length; attempt += 1) {
try {
return await createApplication(idempotencyKey);
} catch (error) {
if (!isRetryable(error) || attempt === delays.length) throw error;
await wait(delays[attempt] + Math.random() * 200);
}
}
Do not retry schema failures, permission failures or a 409 with a new idempotency key. That can create duplicate real-world work.