Limits, retries & errors
How many calls you may make, how to retry without paying twice, and what every error answer means.
This page covers the rules every call shares: rate limits, safe retries, paging and errors. The base address is https://api.vortexdeployer.com/api/v1.
Rate limits#
A rate limit caps how many calls you make per minute. Only reads count. Checking a marketplace order counts as a read too.
| Calls | Per key | Per account |
|---|---|---|
GET and HEAD, and an order check | 300 a minute | 600 a minute |
Every other POST, PATCH, DELETE | no limit | no limit |
An order check is POST /marketplace/orders/:id/check. It moves no funds and only reads where your order stands, so it counts like a GET. See Wallet marketplace.
All the keys on one account share the account's 600. Buys, sells, batches and launches have no per-minute limit. Neither does making a marketplace order. A key's caps and wallet list guard spending instead. See API overview & keys.
Each read answer, an order check too, has three headers about the key's minute:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Reads a minute the key allows. |
X-RateLimit-Remaining | Reads left this minute. |
X-RateLimit-Reset | When the count starts again, in Unix seconds. |
Over the limit, you get 429 and a Retry-After header in seconds. The body has the same number:
{ "code": "rate_limited", "error": "rate limit reached — slow down", "retryAfterSeconds": 12, "traceId": "…" }Wait that many seconds, then go on.
Bad keys count too. After 30 calls with a wrong or revoked key from one IP address in a minute, every call from it gets 429 auth_rate_limited for a minute.
Retry safely#
A network can drop the answer after the work is done. If you just send the call again, you may buy twice.
An idempotency key stops that. It is a name you pick for one operation, sent in the Idempotency-Key header. Send the same name again and the API answers from its record. It does not run the work twice.
curl -s -X POST https://api.vortexdeployer.com/api/v1/buy \
-H "Authorization: Bearer vd_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: buy-7xKX-2026-10-18-0001" \
-d '{ "mint": "7xKX…pump", "walletId": "812", "amountSol": 0.05 }'- Use one on every
POST,PATCHandDELETEthat moves money: buys, sells, batches, launches, claims and tasks. - A Wallet Marketplace order uses its own
requestKeyinstead. See Request key: safe retries. - It is 8 to 128 characters: letters, digits,
-,_and:. Anything else gets400 invalid_idempotency_key. - Make it unique per operation. A new trade needs a new key.
- Keys belong to your account. Two of your API keys share them.
- The answer echoes the key in the
x-idempotency-keyheader.
Without Idempotency-Key, sending a buy again buys again.
What a repeat returns#
| You send | You get |
|---|---|
| The same key and the same body, after the first call ended | The first call's status and body. Nothing runs again. |
| The same key and body while the first call still runs | The API waits about 5 seconds. Then it answers, or gives 409 operation_pending. |
| The same key with a different body | 409 idempotency_conflict. |
A repeated answer has an x-operation-state header:
complete— the operation is over. Itsconfirmedanderrfields show the chain's latest word.pending— a transaction is still on its way. Ask again later with the same key.
operation_pending carries "operationId" (your key) and "pending": true. The first call's transaction is never sent twice. Wait a few seconds and ask again with the same key.
Same key or new key?#
- You got no answer (a timeout or a dropped line): send again with the same key and body.
- You got an answer, even an error: that answer is saved under the key. To try again with a fixed body, use a new key.
A long call can be cut off after about 100 seconds before its answer reaches you. The work goes on. Ask again with the same key to get the result.
Paging#
Long lists are paged with ?limit= and ?offset=.
limitis 1 to 500. Default 200.offsetstarts at 0.X-Total-Countholds the full size of the list.- A
limitout of range gets400 validation_failed.
A few lists page in their own way, like GET /events and GET /marketplace/inventory. Their pages say so.
Errors#
Every error is JSON with the same fields:
{ "code": "insufficient_scope", "error": "this API key does not have the 'trade' scope", "traceId": "9f1c…" }code— a fixed name for the problem. Your code should check this.error— words for people. The wording can change.traceId— a trace id for this one call. Give it to support when you ask for help.
A bad body or query gets validation_failed, and details lists each problem:
{
"code": "validation_failed",
"error": "validation failed",
"details": [ { "path": "amountSol", "message": "Too small: expected number to be >0" } ],
"traceId": "…"
}Some codes add a field that names the limit:
over_trade_capaddsmaxSolPerTrade.over_daily_capaddsdailySolCap.wallet_not_allowedaddswalletId.rate_limitedandauth_rate_limitedaddretryAfterSeconds.
A route that does not exist gets 404 not_found with "no such API route".
Codes#
| Code | Status | What it means and what to do |
|---|---|---|
validation_failed | 400 | The body or query is wrong. Fix what details names. |
invalid_idempotency_key | 400 | The Idempotency-Key header is malformed. |
bad_request | 400 | The API understood the call but will not do it. error says why. |
invalid_api_key | 401 | The key is missing, wrong or revoked. Stop and tell the key's owner. |
unauthorized | 401 | A 401 with no other code. Treat it like invalid_api_key. |
insufficient_scope | 403 | The key lacks the scope this route needs. |
ip_not_allowed | 403 | The call came from an IP address the key does not allow. |
key_restricted | 403 | A key with limits tried something only a key with no limits may do. |
sandbox_key | 403 | A sandbox key sent a real call. Add "dryRun": true. |
wallet_not_allowed | 403 | The wallet is not on the key's wallet list. |
private_key_not_allowed | 403 | A key with a wallet list sent a private key. |
over_trade_cap | 403 | A buy is over the key's max per buy. |
over_daily_cap | 403 | The buy would pass the key's daily cap. |
forbidden | 403 | The thing you named is not yours, or you may not do this. |
not_found | 404 | No such route, or no such item in your account. |
idempotency_conflict | 409 | You used this Idempotency-Key for a different body. |
operation_pending | 409 | The first call with this key still runs. Ask again with the same key. |
conflict | 409 | The call does not fit the current state, like pausing a stopped task. |
payload_too_large | 413 | The body is too big. Most routes take up to 256 KB, POST /launch 15 MB and task calls 10 MB. |
unprocessable | 422 | It cannot be done, like selling a token the wallet does not hold. |
rate_limited | 429 | Too many reads. Wait Retry-After seconds. |
auth_rate_limited | 429 | Too many bad keys from your IP address. Wait a minute. |
internal_error | 500 | Something broke on our side. Note the traceId. |
service_unavailable | 503 | Out of service for a moment. Wait, then ask again. |
A route may also send a code that is not listed here. Then go by the status.
A 503 with operation_pending means the work ran but its answer was not saved. Ask again later with the same key. Do not send it as new.
Each route's statuses and codes are in the OpenAPI document at https://api.vortexdeployer.com/api/v1/openapi.json.
Ask for a feature#
Missing an endpoint, field or stream? In the app, open API and then the Feature requests tab. Fill in Request title and Request details, then click Send request. Your requests and their status show in the same tab.