Don't invest unless you're prepared to lose all the money you invest. This is a high-risk investment and you should not expect to be protected if something goes wrong. Take 2 mins to learn more.

DecryptrDevelopers

Rate limits and quotas

How the Decryptr API counts calls (one per item, weighted by endpoint), the limits per plan, the headers on every response, 429 and Retry-After, and a backoff example.

Everything is counted in calls, and there are three limits on them:

  1. Calls per month. What you pay for. A hard cap with no overage charges.
  2. Calls per minute. A fixed window per clock minute.
  3. Burst. A bucket that holds your plan's maximum calls per request and refills at the per-second rate, so one full request always fits in a full bucket.

Calls: one per item, weighted

A call is counted by what you get back or ask for, not by HTTP request. Most items cost 1 call. Richer items cost more.

  • A list costs its weight for each item it returns. A page of 37 trending coins costs 37 calls. A page of 20 footprint candles costs 40, because a footprint candle weighs 2.
  • A batch costs its weight for each id you ask for. /v1/sentiment/callers?assets=BTC,ETH,SOL,DOGE,XRP costs 5 calls, even if one of the assets has no data.
  • A single lookup has a flat cost: 1 call for /v1/analytics/crowd/BTC, 2 for /v1/coins/BTC, 3 for /v1/liquidations/BTC. A lookup that finds nothing still pays.
  • A search costs 5 calls plus 1 call per result. A search with no results costs 5.
  • A stream connection is free. Each event delivered costs 1 call, taken before it is sent.
  • An empty list costs 1 item's worth, so polling an empty list is not free.
  • /v1/status, /v1/usage and /v1/tombstones are free.
  • Test keys never count towards the month.

Every response tells you what it cost in the X-Decryptr-Cost header. The API reference shows the cost on each endpoint.

EndpointCost in callsReserved before it runs
GET /v1/statusFreeNothing
GET /v1/usageFreeNothing
GET /v1/trending/coins1 call per item returnedlimit
GET /v1/calls/outcomes1 call per item returnedlimit
GET /v1/calls/most-called1 call per item returnedlimit
GET /v1/sentiment/callers1 call per id asked forNumber of ids
GET /v1/sentiment/{asset}1 call per item returnedlimit
GET /v1/analytics/crowd/{asset}1 call, also when not found1
GET /v1/coins/{asset}2 calls, also when not found2
GET /v1/prop/programs1 call per item returnedlimit
GET /v1/levels/rounds1 call per item returnedlimit
GET /v1/levels/rounds/{id}1 call, also when not found1
GET /v1/liquidations/{asset}3 calls, also when not found3
GET /v1/orderflow/delta1 call per item returnedlimit
GET /v1/orderflow/footprint2 calls per item returnedlimit x 2
GET /v1/derivatives/{asset}/funding1 call per item returnedlimit
GET /v1/whales/positions2 calls per item returnedlimit x 2
GET /v1/whales/positioning2 calls per item returnedlimit x 2
GET /v1/calls1 call per item returnedlimit
GET /v1/calls/{id}1 call, also when not found1
GET /v1/callers3 calls per item returnedlimit x 3
GET /v1/callers/{handle}3 calls, also when not found3
GET /v1/traders3 calls per item returnedlimit x 3
GET /v1/traders/batch3 calls per id asked forNumber of ids
GET /v1/traders/{id}3 calls, also when not found3
GET /v1/leaderboard1 call per item returnedlimit
GET /v1/tombstonesFreeNothing
GET /v1/signals1 call per item returnedlimit
GET /v1/signals/{id}1 call, also when not found1
GET /v1/signals/{id}/impact2 calls, also when not found2
GET /v1/sentiment/{asset}/news1 call per item returnedlimit
GET /v1/stream/signals1 call per event delivered, connecting is freeNothing at connect
GET /v1/trending/topics1 call per item returnedlimit
GET /v1/calendar1 call per item returnedlimit
GET /v1/events/{id}/calls1 call, also when not found1
GET /v1/profiles/{handle}1 call, also when not found1
GET /v1/search/people5 calls, plus 1 call per item returned5 + limit
GET /v1/posts1 call per item returnedlimit
GET /v1/posts/{id}1 call, also when not found1
GET /v1/posts/{id}/replies1 call per item returnedlimit
GET /v1/coins/{asset}/posts1 call per item returnedlimit
GET /v1/trending/posts1 call per item returnedlimit
GET /v1/search/posts5 calls, plus 1 call per item returned5 + limit
GET /v1/stream/posts1 call per event delivered, connecting is freeNothing at connect
GET /v1/communities1 call per item returnedlimit
GET /v1/communities/{slug}1 call, also when not found1
GET /v1/communities/{slug}/posts1 call per item returnedlimit
GET /v1/lists/{id}1 call per item returnedlimit
GET /v1/leaderboards/levels1 call per item returnedlimit
GET /v1/traders/{id}/prop3 calls, also when not found3
GET /v1/traders/wallets3 calls per item returnedlimit x 3
GET /v1/communities/{slug}/activity1 call per item returnedlimit
GET /v1/communities/{slug}/members/history1 call per item returnedlimit
GET /v1/rooms1 call per item returnedlimit
GET /v1/rooms/{id}/activity1 call per item returnedlimit
GET /v1/tags/{tag}/volume1 call per item returnedlimit
GET /v1/trending/tags1 call per item returnedlimit
GET /v1/levels/rounds/{id}/distribution2 calls, also when not found2
GET /v1/prop/firms/{firm}/stats1 call, also when not found1
GET /v1/whales/leaderboard1 call per item returnedlimit
GET /v1/market/coins1 call per item returnedlimit
GET /v1/market/coins/{asset}1 call, also when not found1
GET /v1/market/tickers1 call per id asked forNumber of ids
GET /v1/market/candles1 call per item returnedlimit
GET /v1/market/funding1 call per item returnedlimit
GET /v1/market/open-interest1 call per item returnedlimit
GET /v1/market/long-short1 call per item returnedlimit
GET /v1/market/long-short/exchanges1 call per item returnedlimit
GET /v1/market/liquidations/heatmap2 calls per item returnedlimit x 2
GET /v1/market/liquidations/totals1 call per item returnedlimit
GET /v1/market/trending1 call per item returnedlimit

Reserved before it runs

Before a list runs, the API reserves the most it could cost: limit times the calls per item. If your remaining budget cannot cover that, the request is refused with 429 and nothing is read or charged. Ask for a smaller limit to fit. After the request runs, the unused part comes back and you pay only for what was returned.

A worked example

You are on Starter and have 60 calls left this month.

RequestReservedResultCostLeft
/v1/liquidations/BTC3Runs357
/v1/orderflow/delta?asset=BTC&limit=2525Fits, returns 252532
/v1/orderflow/delta?asset=BTC&limit=2525Fits, returns 25257
/v1/orderflow/delta?asset=BTC&limit=252525 does not fit in 7, refused with 429 quota_exceeded07
/v1/sentiment/callers?assets=BTC,ETH,SOL,DOGE,XRP5Runs, DOGE has no data52
/v1/coins/BTC2Runs20
/v1/usage0Runs, free00

Page sizes

Each plan sets the most calls one request may reserve. For searches the 5 call base counts too. The most items per request is that number divided by the endpoint's weight, rounded down. On Pro (50), you can ask for 50 trending coins, or 25 footprint candles. Asking for more is refused with 400 limit_too_large, and the error's max_items says what your plan allows.

When calls run out

Every plan is a hard cap. There are no surprise bills: requests are refused with 429 quota_exceeded until the month resets on the 1st (UTC) or you upgrade. See Plans and pricing.

Limits per plan

The per-second figure is how fast the burst bucket refills. All figures are calls.

PlanCalls / second (refill)Calls / minuteCalls / monthMax calls per request
Developer2201,00010
Starter56050,00025
Pro15300300,00050
Business409001,500,000100
EnterpriseBy contractBy contractBy contractBy contract

Headers on every response

Every authenticated response, including a 429, carries these:

X-Request-Id: 3f6c2a8e-6a1f-4c1e-9d2b-0a5e7c1d9b42
X-Decryptr-Cost: 37
RateLimit-Policy: "burst";q=25;w=1, "minute";q=60;w=60, "month";q=50000;w=2592000
RateLimit: "minute";r=23;t=37
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 23
X-RateLimit-Reset: 37
X-RateLimit-Burst-Remaining: 12
X-Quota-Limit: 50000
X-Quota-Remaining: 48210
HeaderMeaning
X-Decryptr-CostCalls this request was charged.
X-RateLimit-LimitCalls allowed per minute.
X-RateLimit-RemainingCalls left in this minute, after this request.
X-RateLimit-ResetSeconds until the minute window resets.
X-RateLimit-Burst-RemainingCalls left in the burst bucket.
X-Quota-LimitCalls allowed per calendar month (UTC).
X-Quota-RemainingCalls left this month, after this request.
RateLimit-Policy, RateLimitThe same limits in the IETF draft 11 format.
RateLimit-Limit, RateLimit-Remaining, RateLimit-ResetOlder draft names for the minute window.
Retry-AfterOn a 429: seconds to wait before trying again.

/v1/usage returns your plan, limits and calls used as JSON, and is free to call.

Handling 429

A 429 always comes with Retry-After and a problem body whose code says which limit you hit. For rate_limited and quota_exceeded, the body also has limit (burst, minute or quota), calls_requested and retry_after.

CodeWhat to do
rate_limitedWait Retry-After seconds, then retry. If the request alone is bigger than your bucket, ask for a smaller limit.
quota_exceededNot enough calls left this month. Ask for a smaller limit, wait for the reset, or upgrade. Retrying the same request will fail again.
too_many_auth_failuresToo many failed key checks from your client. Fix the key, then wait Retry-After seconds.
stream_limitYou already have your plan's number of open streams (2 on Pro, 10 on Business, shared by the signal and post streams). Close one, or reconnect after the server ends a connection.

Retry rate_limited with exponential backoff and jitter, and respect Retry-After when it is longer:

get-with-backoff.mjs
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

export async function getWithBackoff(url, key, maxTries = 5) {
  for (let attempt = 0; ; attempt++) {
    const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` } });
    if (res.status !== 429) return res;

    const problem = await res.json();
    // Only the request rate is worth retrying; the other 429s will fail again.
    if (problem.code !== "rate_limited" || attempt + 1 >= maxTries) return res;

    const retryAfter = Number(res.headers.get("Retry-After") ?? 1) * 1000;
    const backoff = Math.min(30_000, 500 * 2 ** attempt);
    await sleep(Math.max(retryAfter, backoff) + Math.random() * 250);
  }
}

On this page