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

# Apex Errors and Rate Limits

> Every OrbitFlare Apex error: JSON-RPC codes -32001, -32029, -32602, and -32603, plain HTTP statuses, QUIC admission codes, rate limits, and what to do about each.

## Accepted Does Not Mean Landed

A successful reply means the Apex endpoint holds your transaction and is racing it to the leaders until it lands or its blockhash expires. It does **not** mean the transaction landed. Confirm every send with `getSignatureStatuses` on a Solana RPC. See [Best practices](/apex/best-practices#confirm-every-send).

Apex checks a transaction in this order: API key, rate limit, transaction validity and size, then the tip. The first failed check decides the error. Nothing is sent anywhere until every check passes, so a rejected transaction costs nothing.

## JSON-RPC Errors

| Code     | Meaning                                                                                               | What to do                                                       |
| -------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `-32001` | Unauthorized. The API key is missing or invalid                                                       | Check the `x-api-key` header or `?api-key=` parameter            |
| `-32029` | Rate limited. Your key is over its per-second limit                                                   | Back off briefly and retry. Smooth out bursts                    |
| `-32602` | Invalid transaction or tip. The message says what failed, and states your floor when the tip is short | Fix the transaction. Retrying the same bytes will fail again     |
| `-32603` | Busy. The endpoint is shedding load                                                                   | Retry after a short delay, or fail over to another Apex endpoint |

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "..."
  }
}
```

## Plain HTTP Errors

On `/send` and `/send-bin`, success is HTTP `200` with `{"signature": "..."}`. `/send-batch` replies `200` with `{"attempted": n, "accepted": n, "rejected": n, "results": [...]}`, where each result, in frame order, is either `{"signature": "..."}` or `{"error": "<label>", "message": "..."}`. `/send-bundle` replies `200` with `{"bundle_id": "...", "signatures": ["...", "..."]}`.

Errors are JSON with a machine-readable label and a human-readable message:

```json theme={null}
{ "error": "<label>", "message": "..." }
```

| Status | Meaning                                          | Labels                                                                                                                                              |
| ------ | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401`  | Unauthorized                                     | `unauthorized`                                                                                                                                      |
| `429`  | Rate limited                                     | `rate_limited`                                                                                                                                      |
| `400`  | Invalid request, transaction, or tip             | `invalid`, `malformed`, `no_signatures`, `no_tip`, `below_floor`, `multiple_tips`, `tip_not_static`, `tip_source_not_signer`, `too_large`, `bundle` |
| `408`  | The request body did not arrive within 2 seconds | `timeout`                                                                                                                                           |
| `413`  | The request body is too large                    | `too_large`                                                                                                                                         |
| `503`  | Busy                                             | `busy`                                                                                                                                              |

<Note>
  Branch on the HTTP status first. It is the stable part of the contract. Treat a label you do not recognize under `400` as "fix the transaction".
</Note>

`/send-batch` replies `200` whenever the request itself is well formed, and reports each frame on its own inside `results`. Check `rejected` and each entry rather than the status code alone. See [POST /send-batch](/apex/sending-transactions#post-/send-batch).

The `bundle` label (HTTP `400`) means a [bundle](/apex/bundles) was refused as a whole: more than 4 members, a duplicate member, bundles not available for this key or endpoint, or the block engine refused it. A problem with one member keeps its own label. A member over 1232 bytes comes back as `malformed` with a message naming the 1232 byte limit, two tipped members as `multiple_tips`, and no tipped member as `no_tip`.

### Tip Errors in Detail

| Label                   | What went wrong                                                  | Fix                                                                               |
| ----------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `no_tip`                | No top-level SystemProgram transfer to a published tip account   | Add the [tip instruction](/apex/tips). A transfer made through CPI does not count |
| `below_floor`           | The tip is under your tier's floor. The message states the floor | Raise the tip to at least the floor                                               |
| `multiple_tips`         | More than one tip transfer                                       | Keep exactly one                                                                  |
| `tip_not_static`        | The tip account was loaded through an address lookup table       | Put the tip account in the static account keys                                    |
| `tip_source_not_signer` | The account paying the tip did not sign                          | Fund the tip from a signer                                                        |

## QUIC Admission Codes

A bidirectional QUIC stream answers with one admission code. A unidirectional stream returns nothing, so use a bidirectional stream while you integrate.

| Code | Name             | Rust `AdmissionCode` | JSON-RPC equivalent |
| ---- | ---------------- | -------------------- | ------------------- |
| `0`  | ok               | `Ok`                 | result              |
| `1`  | unauthorized     | `Unauthorized`       | `-32001`            |
| `2`  | rate limited     | `RateLimited`        | `-32029`            |
| `3`  | invalid          | `Invalid`            | `-32602`            |
| `4`  | no tip           | `NoTip`              | `-32602`            |
| `5`  | below floor      | `BelowFloor`         | `-32602`            |
| `6`  | busy             | `Busy`               | `-32603`            |
| `7`  | malformed packet | `MalformedPacket`    | none                |

If the QUIC **handshake** itself is refused, the connection closes with application error `1` (no client certificate), `2` (unknown key), or `3` (too many connections). See [Authentication](/apex/authentication#quic-client-certificate).

In the Rust client, `send_transaction_with_response` turns a rejection into `Error::Rejected { code, message }`, and a transaction over 4096 bytes fails locally with `Error::TooLarge` before anything is sent.

## Which Errors to Retry

| Error                                        | Retry?                                                                                 |
| -------------------------------------------- | -------------------------------------------------------------------------------------- |
| Rate limited (`-32029`, `429`)               | Yes, after a short backoff                                                             |
| Busy (`-32603`, `503`)                       | Yes, after a short delay or on another Apex endpoint                                   |
| Network error or timeout before a reply      | Yes. The endpoint deduplicates by signature, so resending the same transaction is safe |
| Invalid transaction or tip (`-32602`, `400`) | No. Rebuild the transaction                                                            |
| Unauthorized (`-32001`, `401`)               | No. Fix the key                                                                        |

You do not need to resend an **accepted** transaction. Apex already retries it until it lands or the blockhash expires. If it has not landed by then, rebuild it with a fresh blockhash and send the new transaction.

## Rate Limits

Rate limits are **per API key** and set by the key's **tier**. The limit counts transactions per second across every transport: JSON-RPC, the HTTP routes, and QUIC all draw from the same allowance, and each frame of a batch counts as one transaction.

When you exceed the limit you get `-32029`, HTTP `429`, or admission code `2`. The rejected transaction is not queued, so resend it after a moment if it still matters.

Your tier's limit and tip floor are shown next to the key in the [OrbitFlare dashboard](https://orbitflare.com/dashboard) under **Dashboard > Apex**. To raise them, contact the team on [Discord](https://discord.gg/orbitflare).

## Limits at a Glance

| Limit             | Value                                                                            |
| ----------------- | -------------------------------------------------------------------------------- |
| Transaction size  | Legacy and v0: 1232 bytes. [v1](/apex/transaction-v1): 4096 bytes                |
| Batch size        | 16 transactions per `/send-batch` request                                        |
| Bundle size       | 1 to 4 transactions, 1232 bytes each                                             |
| QUIC packet size  | 4160 bytes                                                                       |
| QUIC connections  | 128 per API key, 64 per address                                                  |
| QUIC idle timeout | 30 seconds. The Rust client pings every second                                   |
| Connections       | One QUIC client per process and Apex endpoint is enough. Streams multiplex on it |
