Core concepts
The rules every endpoint and stream follows. Read this once before integrating.
Base URLs and access
- HTTP
https://data.dydt.ai/v1- WebSocket
wss://data.dydt.ai/ws- Authentication
- Send your key as
Authorization: Bearer <key>. Create keys on API keys; plans and payment are on pricing and billing. - Browser calls
- Keys are secrets. Call the API from your server and never ship a key in a browser or mobile app.
Response envelope
Every HTTP response is JSON with the same four fields. code is 0 on success; data holds the result, an array for lists and an object otherwise. Lists that page add pagination.
{ "code": 0, "error": null, "message": "OK", "data": [ … ], "pagination": { "next_cursor": "eyJvZmZzZXQiOjUwfQ", "has_more": true } }
On failure code is a stable status code (the HTTP status times ten, plus a digit for specific cases), error is its name for your code to branch on, and message is for people.
{ "code": 4033, "error": "PLAN_REQUIRED", "message": "This endpoint needs the Pro or Scale plan", "data": null }
Status codes
Codes you can receive from data.dydt.ai. They are stable; new ones are only added.
- 0
- OK. error is null.
- 4000
- BAD_REQUEST: a parameter failed validation; message names it.
- 4010
- UNAUTHENTICATED: no API key was sent.
- 4013
- INVALID_API_KEY: the API key is invalid or revoked.
- 4033
- PLAN_REQUIRED: the endpoint needs the Pro or Scale plan.
- 4040
- NOT_FOUND: the route or resource does not exist.
- 4290
- RATE_LIMITED: see the RateLimit-* headers and Retry-After.
- 4291
- QUOTA_EXCEEDED: monthly request quota used; see X-Quota-* headers.
- 4292
- TOO_MANY_IN_FLIGHT: wait for a request to finish.
- 5000
- INTERNAL: unexpected server error. Retry with backoff.
- 5020
- UPSTREAM_FAILED: an upstream dependency failed.
- 5030
- UNAVAILABLE: temporarily unavailable. Retry with backoff.
- 5040
- TIMEOUT: the request took too long; narrow it and retry.
Errors
- 200
- Success. code is 0 and data holds the result; lists can be empty.
- 400
- A parameter failed validation, or the request named a parameter the endpoint does not take. message names it, e.g. "limit must be an integer between 1 and 100".
- 401
- Missing or invalid API key.
- 403
- The endpoint needs the Pro or Scale plan.
- 404
- The route or the requested resource does not exist.
- 429
- Rate limit, monthly quota or in-flight limit exceeded. Wait for Retry-After, or until X-Quota-Remaining resets.
- 5xx
- Server or upstream failure. Retry with exponential backoff and jitter.
Pagination
Every endpoint that pages uses the same cursor. Keep requesting with the returned cursor until has_more is false.
- limit
- Rows per page. Every list endpoint documents its default and maximum.
- pagination.next_cursor
- Returned by endpoints that page. Pass it back unchanged as cursor; it is opaque.
- pagination.has_more
- False on the last page, where next_cursor is null.
Tokens and pools
A token is identified by its mint address. Its price, candles, and trades come from the pools it trades in, and one token can have several. Token endpoints take token_address; pool endpoints, candles, the pool_trades stream, and the chart embed take pool_address.
GET /tokens/{token_address}/trades reads a token's trades across every pool it trades in, bonding curve included, and each trade names its pool_address and dex. GET /pools/{pool_address}/trades reads one pool and the bonding curve it migrated from.
token_addressThe mint. One per token, never changes.- Before graduationBonding curve
pool_addressThe launchpad pool, e.g. pump.fun. Trading starts here. - After graduationAMM pool
pool_addressCreated when the curve fills, e.g. PumpSwap, quoted in SOL. - Any timeAnother AMM pool
pool_addressAnyone can add a pool on another venue or quote asset, e.g. USDC.
GET /pools?base_address=TOKEN_ADDRESS. After graduation, GET /pools/POOL_ADDRESS names the pool that replaced it.Units and identifiers
- Money
- Every amount names its unit in a suffix: _usd, _sol, or _quote (the pool quote asset, usually SOL). Raw on-chain integers end in _raw or _lamports and are strings.
- Timestamps
- Unix milliseconds, in fields ending in _at.
- Percentages
- Fields ending in _pct are 0 to 100. Price changes can be negative or above 100.
- Addresses
- Base58 Solana addresses named by what they are: token_address, pool_address, wallet_address, base_address, quote_address. Transactions are tx_hash.
- Windowed metrics
- windowed is columnar: t lists the windows and every other array holds one entry per window at the same index. Money arrays hold [quote, usd] pairs.
- Images
- image_url fields are absolute URLs on the dydt CDN.
WebSocket lifecycle
- After a disconnect, back off and start again from 1Your app → HTTP API
GET candles, trades, pool - HTTP API → Your app
snapshot - Your app → WebSocket
{ "type": "auth", "key": … } - WebSocket → Your app
{ "type": "auth", "status": "ok" } - Your app → WebSocket
{ "type": "subscribe", "stream", "payload" } - WebSocket → Your app
events: { "stream", "data" } - Your app → WebSocket
{ "type": "ping" } every 15 s - WebSocket → Your app
pong - Your app → WebSocket
{ "type": "unsubscribe", … } when done
- Load the current state over HTTP.
- Open one connection and authenticate with
{"type":"auth","key":"…"}as the first frame. - Send a
subscribeframe for each stream you need. - Send
{"type":"ping"}every 15 seconds. The server answers withpong. - On disconnect, reconnect with exponential backoff, subscribe again, and reload the HTTP state. Missed events are not replayed.
- Send
unsubscribewith the same payload when you no longer need a stream.
Unknown streams and invalid payloads are ignored without an error frame. If no events arrive, check the payload in the stream explorer.
Limits and stability
- Rate limits
- Every response carries
RateLimit-Limit,RateLimit-Remaining,RateLimit-ResetandX-Quota-Remaining. Over the limit, requests return 429 withRetry-After. - Streams
- Every message we send on a stream counts toward the monthly message allowance (20 times the request quota); control frames like auth, errors and pong do not. Each subscription uses one watched item per pool, wallet or feed it names, shared across all of your connections. Past 110% of the allowance, streams close with 4429.
- Query bounds
- Candles return up to 1000 per request. Trade history covers the last 30 days on every plan; without
start_time,/tradesdefaults to the last 24 hours. - Billing
- Paid in USDC or SOL (at a rate locked for 30 minutes) from any wallet app or your dydt trading wallet; 3, 6 and 12 month terms are discounted. Switching plans converts your remaining time at the new plan's price. After expiry, requests keep working for a 2-hour grace period (
X-Subscription-Grace: true), then fall back to the Free plan; open streams close with 4402. - Versioning
- Routes live under
/v1. New fields can be added at any time, so ignore unknown fields. Every change is listed in the changelog.