Handle errors and retries
Classify 0Bit API errors, retry only transient failures, and preserve request ids for support.
Good retry behavior prevents duplicate sessions, retry storms, and confusing support cases. Treat validation, authentication, authorization, and state conflicts as terminal until a human or code change fixes the input.
Log request ids, not secrets
Capture response status, error code or class, X-Request-Id, your local attempt id, and the operation name. Redact authorization headers, client secrets, webhook secrets, and customer PII.
Error handling matrix
| Status class | Typical meaning | Retry? | Action |
|---|---|---|---|
400 | Validation or malformed request. | No | Fix request construction. |
401 | Missing or malformed credential. | No | Check server configuration. |
403 | Credential, mode, entitlement, or origin rejected. | No | Fix configuration or approval state. |
404 | Resource missing or not scoped to this credential. | No | Check identifiers and ownership. |
409 | State or idempotency conflict. | Sometimes | Read current state before retrying. |
429 | Rate limited. | Yes, with backoff | Respect documented retry hints. |
5xx | Transient server or upstream failure. | Yes, bounded | Retry with idempotency and jitter. |
| Network timeout | Unknown result. | Yes, bounded | Retry the same operation with the same idempotency key. |
Retry flow
Bounded retry helper
async function retryApiWrite<T>(operation: () => Promise<T>) {
for (let attempt = 0; attempt < 4; attempt += 1) {
try {
return await operation();
} catch (error) {
if (!isRetryable(error) || attempt === 3) throw error;
await delay(backoffWithJitter(attempt));
}
}
throw new Error('retry_exhausted');
}