v2.4 CURRENT PROTOCOLHTTP

Error Codes

The Incapon API returns 2xx for successful requests, 4xx for client errors and 5xx for server-side problems. Whatever the status code, the error body always has the same shape, so a single error handler covers every tool.

The error body

{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "Your balance is too low for this operation.",
    "request_id": "req_8f2a91c4d7"
  }
}

code is stable and meant for machines; build your logic on it. message is for humans and may change. Write request_id to your logs: when you contact support, this id lets us find the request within seconds.

Status codes

StatuscodeMeaningRetry
400BAD_REQUESTThe request body is malformed or incomplete.No
401UNAUTHORIZEDThe key is missing, invalid or revoked.No
402INSUFFICIENT_CREDITSThe balance does not cover this job.After topping up
403FORBIDDENThe key's scopes or IP address do not allow this endpoint.No
404NOT_FOUNDThe resource does not exist or belongs to another team.No
409CONFLICTThe resource is being changed by another operation.Yes
422VALIDATION_FAILEDFields are well-formed but semantically wrong.No
429RATE_LIMITThe limit of 600 requests per minute was exceeded.Yes
500INTERNALUnexpected server error.Yes
503UNAVAILABLEThe service is temporarily busy or under maintenance.Yes

Retrying with exponential backoff

Do not repeat a retryable request immediately. On a 429, first wait as long as the Retry-After header says; in other cases double the wait on every attempt and add random jitter. After five attempts, pass the error up.

async function withRetry(fn, maxAttempts = 5) {
  for (let attempt = 0; ; attempt++) {
    const res = await fn();
    const retryable = [409, 429, 500, 503].includes(res.status);
    if (!retryable || attempt + 1 >= maxAttempts) return res;

    // Honour Retry-After if present, otherwise 1s, 2s, 4s, 8s + jitter
    const retryAfter = Number(res.headers.get('retry-after'));
    const delay = retryAfter ? retryAfter * 1000 : 2 ** attempt * 1000 + Math.random() * 250;
    await new Promise((r) => setTimeout(r, delay));
  }
}
Retry resource-creating requests safely

Send an Idempotency-Key header with POST requests. A repeat with the same key returns the result of the first request, so a retry never creates two monitors or a job that is charged twice. The official SDKs do this, and the backoff, on their own.

When you get a 402, check the balance instead of retrying; Auto Top-Up all but eliminates this error in production.

Next Steps & Guides

Was this guide helpful?

Your feedback helps us improve our documentation.