dydt.aiTerminalTerminalDevelopers
DocsAPI referenceChangelog
Open terminalGet API key

GET STARTED

OverviewQuickstartCore concepts

REFERENCE

HTTP endpointsWebSocket streams

ACCOUNT

API keysPricing and billing

GUIDES

AI agentsBuild your own agentChart embedChangelog

SPECS

OpenAPI JSON ↗AsyncAPI JSON ↗
Developers/Get started

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.

Success
{
  "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.

Error
{
  "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.

Tokentoken_addressThe mint. One per token, never changes.
  1. Before graduationBonding curvepool_addressThe launchpad pool, e.g. pump.fun. Trading starts here.
  2. After graduationAMM poolpool_addressCreated when the curve fills, e.g. PumpSwap, quoted in SOL.
  3. Any timeAnother AMM poolpool_addressAnyone can add a pool on another venue or quote asset, e.g. USDC.
List a token's pools with 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 appkeeps one connectionHTTP APIcurrent stateWebSocketlive events1GET candles, trades, pool2snapshot3{ "type": "auth", "key": … }4{ "type": "auth", "status": "ok" }5{ "type": "subscribe", "stream", "payload" }6events: { "stream", "data" }7{ "type": "ping" } every 15 s8pong9{ "type": "unsubscribe", … } when done
  1. After a disconnect, back off and start again from 1Your app → HTTP APIGET candles, trades, pool
  2. HTTP API → Your appsnapshot
  3. Your app → WebSocket{ "type": "auth", "key": … }
  4. WebSocket → Your app{ "type": "auth", "status": "ok" }
  5. Your app → WebSocket{ "type": "subscribe", "stream", "payload" }
  6. WebSocket → Your appevents: { "stream", "data" }
  7. Your app → WebSocket{ "type": "ping" } every 15 s
  8. WebSocket → Your apppong
  9. Your app → WebSocket{ "type": "unsubscribe", … } when done
HTTP snapshotLive eventsMissed events are not replayed; the new snapshot fills the gap.
  1. Load the current state over HTTP.
  2. Open one connection and authenticate with {"type":"auth","key":"…"} as the first frame.
  3. Send a subscribe frame for each stream you need.
  4. Send {"type":"ping"} every 15 seconds. The server answers with pong.
  5. On disconnect, reconnect with exponential backoff, subscribe again, and reload the HTTP state. Missed events are not replayed.
  6. Send unsubscribe with 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-Reset and X-Quota-Remaining. Over the limit, requests return 429 with Retry-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, /trades defaults 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.
Support
Message us on Telegram or X with the route or stream, the UTC time, the HTTP status or connection state, and the request. Never share private keys or seed phrases.