# Requests & Errors > How Ora API requests and responses are shaped, what each error means, and the rate limits. ### Requests and responses - **JSON in, JSON out.** Send `Content-Type: application/json` with a body, and only with a body. - **Envelope.** Every response has `"success": true` or `"success": false`. Check it, not only the status code. - **Token amounts** are raw base units as decimal *strings*, because they overflow JavaScript numbers: `"250000000000"`. Divide by 10 to the power of the token's decimals to display them (most Solana launchpad tokens use 6 decimals, EVM tokens 18). - **Native amounts.** Inputs named `…Sol` are plain decimal numbers of the chain's gas asset (`0.5`). Raw native amounts in responses are lamports on Solana and wei on EVM chains. - **Addresses.** Solana addresses are base58, EVM addresses `0x`-hex. `{address}` and `{mint}` in a path are a token's mint (Solana) or contract (EVM). - **Request IDs.** Every response carries an `X-Request-ID` header. Send your own (a UUID v4) to tie a call to your logs; Ora carries it through every service it touches. - **Timestamps** are ISO 8601 in UTC. ### Errors A failed call answers with `"success": false` and an `error`. When Ora forwards the failure from one of its services, `error` is a short reference code (like `M4K8T`) and `message` carries the readable reason. ```json { "success": false, "error": "M4K8T", "message": "…readable reason…" } ``` | Status | Meaning | What to do | |---|---|---| | `400` | The body or a parameter is invalid. | Read `error` and `message`: they name the field. Don't retry unchanged. | | `401` | No key, a malformed key, or a key that was rotated or revoked. | Check the header and the key. Don't retry in a loop: refused keys are rate limited per IP. | | `403` | API access is off on the account. | Ask Ora support to turn API access on. | | `404` | Not found, or not yours. Ora never reveals whether something you don't own exists. | Check the ID or address, and that it belongs to your account. | | `409` | The resource is not in a state that allows this (not launched yet, already running…). | Read the state, then act. | | `429` | Rate limit reached. | Back off: see [Rate limits](#rate-limits). | | `502` | A service behind the API failed. | Retry with backoff. If it persists, send the `error` code and the `X-Request-ID` to Ora support. | | `503` | Temporarily unavailable (a dependency is down or busy). | Retry with backoff. | > **Warning:** **Writes are not idempotent.** A `502` or a timeout on a buy, sell or launch does not mean nothing happened. Read the state (positions, trades, the token stream) before you retry a write. ### Rate limits | Budget | Limit | Counted per | Covers | |---|---|---|---| | API requests | 100 per minute | Account | Every request made with your key, streams included (one per connection). Separate from the app's own budget: a busy script never slows your app session. | | Refused keys | 20 per minute | IP address | Requests whose key is malformed or unknown (`401`). Past it, they get `429`. | Windows are fixed one-minute windows. A `429` carries no `Retry-After` header: wait, then retry with exponential backoff starting at 1 second and capped at 60. Spread batch jobs over time instead of bursting. ```js title="retry.mjs" export async function withRetry(fn, tries = 6) { for (let i = 0; ; i++) { try { return await fn(); } catch (err) { const retryable = err.status === 429 || err.status === 502 || err.status === 503; if (!retryable || i + 1 >= tries) throw err; await new Promise((r) => setTimeout(r, Math.min(60_000, 1000 * 2 ** i))); } } } // Reads only. Before retrying a write, check what already happened. ```