DexTrending DexTrendingDocs
Main site Open panel

API for developers

Errors and rate limits

Every status code the API returns, what causes it, and the rate limit you are working within.

Errors return a matching HTTP status and a JSON body with a single error string. There is no error code enum; the status plus the message is the contract.

{ "error": "Package already used" }

Status codes

StatusMeaningWhat to do
200Success
201Campaign createdReturned only by POST /campaigns
400Bad request A required field is missing, the chain is unknown, or the package group does not match the chain. Nothing was consumed.
401Authentication failed Key missing, malformed, or revoked. Check the header.
403Account suspendedContact support.
404Not found The package does not belong to your account, or the token address does not resolve on that chain.
405Method not allowed The Allow header lists what the endpoint accepts.
409Conflict The package was already used, most often by a duplicate request. Nothing was double-spent.
429Rate limit reachedBack off and retry.
500Server error Retry once. If it persists, send the time and endpoint to support.

Rate limit

120 requests per minute per account, across all endpoints and all of your keys. Exceeding it returns:

{ "error": "Rate limit reached, 120 requests per minute" }

The limit is generous for what the API does — campaigns change state over hours, not seconds. If you are hitting it, you are almost certainly polling harder than you need to.

Duplicate launches

A package can only be consumed once. If a launch request is retried after a timeout and the first one actually succeeded, the second returns 409 rather than creating a second campaign.

If a launch times out, do not blindly retry. Call GET /campaigns first and check whether the campaign exists.

Handling errors

async function dt(path, options = {}) {
  const res = await fetch(BASE + path, {
    ...options,
    headers: { "X-API-Key": KEY, "Content-Type": "application/json", ...(options.headers || {}) }
  });

  const body = await res.json().catch(() => ({}));

  if (res.status === 429) {
    await new Promise(r => setTimeout(r, 60000));
    return dt(path, options);
  }
  if (!res.ok) {
    const err = new Error(body.error || `HTTP ${res.status}`);
    err.status = res.status;
    throw err;
  }
  return body;
}

Retry 429 and 500. Do not retry 400, 401, 404 or 409 — those describe a request that will fail identically the second time.

Questions

What is the rate limit?
120 requests per minute per account, shared across all endpoints and all of your keys.
My launch request timed out. Should I retry?
Check GET /campaigns first. If the campaign exists the launch succeeded, and a retry would return 409 rather than creating a second one.
Which errors are worth retrying?
Only 429 and 500. A 400, 401, 404 or 409 describes a request that will fail the same way again.