Skip to main content

Response envelope

The envelope is not uniform across the surface — it depends on the endpoint family. Enveloped (legacy /api/v1/* + raw stats/swaps):
These endpoints wrap success payloads: /api/v1/pairs, /api/v1/candles, /api/v1/candles/latest, /api/v1/stats, /api/v1/top-movers, /api/v1/protocols (and the raw /stats/*, /swaps/* families). Top-level (no wrapper): newer endpoints return the payload directly — no success/data keys:
  • /screener, /search, /trending, /tokens/{mint}/intel, /tokens/{mint}/risk
For example, /screener returns { results, total_matches, limit, offset, warnings } at the top level. Errors are always enveloped, even for the top-level endpoints, and error is an object:
Branch on error.code (the codes). error.message is for humans and is not a stable format; a 5xx message is generic and never carries the internal cause.
  • /screener: a malformed mint, mints[] or creator filter is a 400 INVALID_PARAM (message invalid parameter: invalid_filter:mint|creator|mints). An unsupported filter (e.g. risk_score) instead stays 200 and adds a note to the warnings[] array.
  • /search: a malformed creator (or deployer) or mints is a 400 INVALID_PARAM (invalid_filter:creator or invalid_filter:mints). mint on /search is matched as text, like query, and is never rejected. An unsupported filter stays 200 with a warnings[] note, as on /screener.
  • /tokens/{mint}/intel and /tokens/{mint}/risk: a malformed mint is a 400 INVALID_PARAM, an unknown mint a 404 NOT_FOUND, and a failed lookup a 503 UNAVAILABLE (retry). A failed lookup is never reported as a 404; /tokens/{mint}/risk answers 504 GATEWAY_TIMEOUT if its lookup times out.
  • /tokens/{mint}/holders, /holders/top, /snipers, /insiders, /smart-money and /whales: a malformed mint is a 400 INVALID_PARAM on every tier.
  • Not on this shape yet: /swaps/* and /stats/* send a flat { "error": "invalid_parameter", "message": "..." } (their 401 and 429 carry the error object but no success), and /tokens/{mint}/concentration sends { "error": "..." }. They are being moved to the envelope; until then, if error is a string, treat it as the message.
Streaming protocols (WebSocket, gRPC) use protocol-native error frames — see the WebSocket and gRPC pages.

Base paths

Endpoints live under different base paths, and one is served by a separate service: All paths share the same host, https://api.dexploit.dev, and the same Authorization / API-key auth.

Rate limits

Dexploit’s pricing model is capped requests-per-second, unlimited monthly usage. Pick a tier that matches your sustained throughput; there is no monthly volume to budget against. The cap is strict per second. Requests are counted in fixed one-second windows (rps_window_secs: 1 in /credits), and the first request over the cap within a second gets a 429. There is no burst allowance above it: a Free-tier client gets 20 requests in any one second, not more by staying quiet the rest of the minute.

Inspecting your usage

Call GET /credits at any time to see your current tier, RPS cap, requests used in the current window, and feature flags:
monthly_used is informational. There is no monthly cap on Dexploit — the field shows your cumulative request count for the current calendar month so you can size up your typical load.

Rate limiting

When you exceed your tier’s RPS cap you get HTTP 429 with code: "RATE_LIMIT_EXCEEDED". Back off and retry. Windows are one second long, so a short backoff is enough; GET /credits shows the current window’s usage.

Tier-locked features

Some endpoints are paid-tier-only. Free tier callers get HTTP 200 with tier_locked: true rather than a 429:
This keeps client code simple — same response shape, an extra flag — and lets your UI render an upsell where data would be without an error-handling branch. Currently tier-locked endpoints: /tokens/{mint}/smart-money, /tokens/{mint}/whales.

Streaming caps

Each API key has one allowance of concurrent streams, set by its tier. Every open stream on every transport counts against it: a gRPC dexploit.v1.SwapStream stream, a gRPC dexploit.v1.PriceStream stream, and a /ws or /ws/swaps WebSocket. The allowance is counted per streaming server today, so while your streams are spread across servers you may be allowed more than your tier’s cap. Do not rely on that: the cap will be enforced across all servers. Opening a stream past the cap is refused once the cap is reached on the server that receives it: gRPC returns RESOURCE_EXHAUSTED (stream cap exceeded; tier=… cap=…), and a WebSocket is closed with code 1013. A slot is freed as soon as its stream closes. The wallet_tags filter is Pro+ only — on lower tiers the filter is silently dropped and the response carries x-dexploit-tier-locked-filter: wallet_tags metadata. See gRPC: SwapStream for the full reference.

Error codes