Bitcall logoBitcall API
The Gateway

Errors

One error shape, eleven codes, and what to do about each.

Every failure — from any product, at any layer — has the same shape:

{
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Your account balance is too low for this operation.",
    "requestId": "9f1c7b2e-4a83-4d21-9c55-1f0b3a7e2d64"
  }
}

Branch on code, never on message. The code is contract; the message is prose we may improve. requestId is the same value as the x-request-id response header — quote it when you contact support and we can find your exact request.

fields appears on validation failures only, naming the offending fields without repeating their values:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request is not valid. See `fields` for what to correct.",
    "requestId": "…",
    "fields": ["body.msisdns", "query.pageSize"]
  }
}

The codes

These eleven are the whole vocabulary. Nothing else is ever returned — and note there is no 403: a call your key is not allowed to make answers 401, like any other credential problem.

Your request needs changing

CodeHTTPWhat to do
VALIDATION_ERROR400Fix the fields listed in fields. Retrying unchanged will fail identically.
NOT_FOUND404The identifier does not exist, or is not yours. See below.
CONFLICT409The resource is not in a state that allows this — an order already cancelled, a job already finished.

Your credentials

CodeHTTPWhat to do
AUTHENTICATION_REQUIRED401You sent no credentials. Add x-key-id and x-api-secret.
INVALID_API_KEY401The credentials you sent were not accepted.

INVALID_API_KEY is deliberately one answer to several situations: a key that does not exist, a wrong secret, a revoked key, an IP outside the key's allowlist, and a key that is not allowed to make this particular call. Distinguishing them would let someone probe which key ids are real without holding a secret.

So if your credentials are definitely correct, check that the key is still active and that you are calling from an allowlisted address. Quote the requestId and support can say exactly which check failed.

Something is unavailable

CodeHTTPWhat to do
INSUFFICIENT_BALANCE409Top up. Retrying without doing so will fail identically.
PRODUCT_UNAVAILABLE409This product cannot be sold right now. Try another, or retry later.
RATE_LIMITED429Wait for the interval in the Retry-After header, then retry.
SERVICE_UNAVAILABLE503A dependency is temporarily down. Retry with backoff.
SERVICE_RESPONSE_INVALID502A downstream service answered in a way that does not match our contract. We rejected it rather than pass it on. Retry; if it persists, report it with the requestId.
INTERNAL_ERROR500Our bug. Retry once, then report it with the requestId.

Which errors are worth retrying

BehaviourCodes
Do not retry — the outcome will not changeVALIDATION_ERROR · NOT_FOUND · CONFLICT · AUTHENTICATION_REQUIRED · INVALID_API_KEY
Retry after actingINSUFFICIENT_BALANCE (top up) · RATE_LIMITED (wait for Retry-After)
Retry with backoffSERVICE_UNAVAILABLE · SERVICE_RESPONSE_INVALID · INTERNAL_ERROR · PRODUCT_UNAVAILABLE

Retrying an operation that spends money can spend it twice. A purchase, a top-up, an OTP rental and a lookup submission all take effect on every call, and there is no key or header that makes a retry safe.

If one of those requests times out or fails in a way that leaves the outcome unknown, do not resend it blind. Read the resource back first — list your orders, or poll the order or job the first attempt would have created — and only retry once you know nothing was created. x-request-id from the failed attempt lets us confirm what happened if you cannot tell.

A 404 never confirms someone else's data

If you ask for an identifier that belongs to another account, you get exactly the same 404 NOT_FOUND as for an identifier that has never existed. The two are indistinguishable on purpose: an answer that distinguished them would confirm that a guessed order id is real and belongs to somebody.

So a 404 means "not yours, or not a thing" — never "exists, but you may not see it".

On this page