> ## Documentation Index
> Fetch the complete documentation index at: https://docs.otpbay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> HTTP status codes and error codes returned by the OTPBay API.

OTPBay uses standard HTTP status codes. `2xx` means success, `4xx` means something is wrong with the request, and `5xx` means a temporary problem on our side.

Every error has the same JSON body:

```json theme={null}
{
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Insufficient balance for this verification."
  }
}
```

<ResponseField name="error.code" type="string">
  A stable, machine-readable code. Branch on this in your code.
</ResponseField>

<ResponseField name="error.message" type="string">
  A human-readable explanation. For validation errors it names each invalid field, for example `to: Must be a valid international phone number (E.164)`. The wording can change, so don't parse it.
</ResponseField>

<Note>
  A wrong verification code is not an error. [Check a code](/api-reference/verify/check) returns `200` with `"valid": false`.
</Note>

## Status codes

| Status | Meaning                                                             |
| ------ | ------------------------------------------------------------------- |
| `200`  | Success.                                                            |
| `201`  | The message or verification was created.                            |
| `400`  | The request is malformed — invalid JSON or a malformed `sid`.       |
| `401`  | The API key is missing or invalid.                                  |
| `402`  | Your balance is too low.                                            |
| `403`  | The IP address isn't allowed, or the channel is turned off.         |
| `404`  | The object doesn't exist in this project.                           |
| `409`  | The object is in a state that doesn't allow this action.            |
| `422`  | The request is well-formed but a field is invalid or can't be used. |
| `503`  | A temporary problem. Retry with exponential backoff.                |

## Error codes

### Authentication

| Status | Code              | Description                                                                                                                        |
| ------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `401`  | `MISSING_API_KEY` | Send `Authorization: Bearer <key>`.                                                                                                |
| `401`  | `INVALID_API_KEY` | The key doesn't exist or was deleted.                                                                                              |
| `403`  | `IP_NOT_ALLOWED`  | The project's IP allowlist doesn't include your address. See [Authentication](/authentication#restrict-keys-to-your-ip-addresses). |

### Request

| Status | Code                   | Description                                                                                             |
| ------ | ---------------------- | ------------------------------------------------------------------------------------------------------- |
| `400`  | `INVALID_JSON`         | The body isn't valid JSON.                                                                              |
| `400`  | `INVALID_MESSAGE_SID`  | The `sid` in the path doesn't have the right prefix (`VE`, `SM` or `TG`) followed by 24 hex characters. |
| `400`  | `INVALID_E164`         | The phone number isn't in international format.                                                         |
| `404`  | `NOT_FOUND`            | The path doesn't exist.                                                                                 |
| `422`  | `INVALID_REQUEST_BODY` | A field is missing, invalid, or not allowed. `message` lists each problem. Unknown fields are rejected. |

### Billing

| Status | Code                   | Description                                                                          |
| ------ | ---------------------- | ------------------------------------------------------------------------------------ |
| `402`  | `INSUFFICIENT_BALANCE` | Your balance doesn't cover the price. [Add funds](/billing#add-funds) and try again. |

### Channels

| Status | Code                     | Description                                                                                                       |
| ------ | ------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `403`  | `CHANNEL_DISABLED`       | SMS or Telegram is turned off for this project.                                                                   |
| `403`  | `VERIFY_DISABLED`        | Verify is turned off for this project.                                                                            |
| `422`  | `SENDER_ID_REQUIRED`     | No `from` and no default sender ID, or no sender ID in Verify settings.                                           |
| `422`  | `SENDER_ID_NOT_APPROVED` | The sender ID isn't approved for this project.                                                                    |
| `422`  | `DESTINATION_NOT_PRICED` | SMS to this destination isn't supported yet.                                                                      |
| `422`  | `TELEGRAM_REJECTED`      | Telegram refused the request, for example because the number has no Telegram account. The reason is in `message`. |

### Objects

| Status | Code                         | Description                                                                     |
| ------ | ---------------------------- | ------------------------------------------------------------------------------- |
| `404`  | `VERIFICATION_NOT_FOUND`     | No verification with this `sid` in your project.                                |
| `404`  | `SMS_MESSAGE_NOT_FOUND`      | No SMS with this `sid` in your project.                                         |
| `404`  | `TELEGRAM_MESSAGE_NOT_FOUND` | No Telegram code with this `sid` in your project.                               |
| `409`  | `VERIFICATION_NOT_PENDING`   | The verification is already `approved`, `expired` or `failed`. Start a new one. |
| `409`  | `TELEGRAM_NOT_SENT`          | The Telegram code never reached Telegram, so it can't be verified.              |

### Temporary

| Status | Code                      | Description                                                                                   |
| ------ | ------------------------- | --------------------------------------------------------------------------------------------- |
| `503`  | `QUEUE_UNAVAILABLE`       | The SMS was saved with status `enqueue_failed` but couldn't be queued. Send it again.         |
| `503`  | `TELEGRAM_UNAVAILABLE`    | Telegram can't be reached right now.                                                          |
| `503`  | `TELEGRAM_NOT_CONFIGURED` | Telegram isn't available on this server.                                                      |
| `503`  | `PRICING_NOT_CONFIGURED`  | SMS prices aren't available right now.                                                        |
| `500`  | `INTERNAL_ERROR`          | Something went wrong on our side. Contact [support](mailto:hello@otpbay.com) if it continues. |

## Retrying

* Retry `503` and `500` errors with exponential backoff.
* Don't retry `4xx` errors unchanged — fix the request first.
* Starting a verification or sending a message isn't idempotent. A retry after a timeout can send a second message, so check for the first one before you retry if you can.
