Skip to content

Frames ​

All client commands and server responses are JSON objects with an op field.

Authenticate ​

Pass the API key in the URL, or send it as the first message:

json
{ "op": "auth", "key": "tsk_live_..." }

Use the message form when you do not want the key in the WebSocket URL.

Subscribe ​

json
{
  "op": "subscribe",
  "id": 1,
  "stream": "token_trades",
  "params": {
    "mint": "DD9e...",
    "detail": "full"
  }
}
FieldDescription
opMust be "subscribe"
idClient correlation id; server responses to the command carry it
streamOne of the eight stream names
paramsStream-specific target, filters, and detail options
cursorOptional replay cursor, beside stream rather than inside params
subOptional name for the subscription; the server assigns one if you omit it

The server acknowledges a successful subscription and returns its name:

json
{ "op": "ack", "id": 1, "sub": "tt_1" }

That name arrives in every event from the subscription, and it is what you pass to unsubscribe.

id and sub ​

Two identifiers with two different jobs, easy to mix up:

  • id is yours, per command. It comes back in the ack or error so you know which command was answered. Nothing else uses it.
  • sub identifies the subscription itself. It arrives in every event, and in notices about that subscription.

Naming your own subscriptions ​

Pass sub on subscribe and the subscription answers to your name instead of a generated one:

json
{
  "op": "subscribe",
  "id": 1,
  "stream": "token_trades",
  "sub": "wsol-chart",
  "params": { "mint": "So11111111111111111111111111111111111111112" }
}

Events then arrive with "sub": "wsol-chart", which saves you a lookup table from generated ids to whatever the subscription feeds on your side.

A name is up to 64 characters and has to be free on that connection; reusing one returns duplicate_subscription. Two different connections may both use wsol-chart. Names belong to subscriptions rather than to targets, so the same mint at basic and at full is two subscriptions and needs two names.

Leave sub out and the server generates one like tt_1 — a stream code and a counter. Treat generated names as opaque: the counter restarts when the service does, so nothing in your code should parse them.

Parameter validation ​

  • A list accepts at most 50 values.
  • A string accepts at most 64 characters.
  • Unknown parameters fail with invalid_params, so misspellings are not silently ignored.
  • Required stream targets (mint or wallet) must be valid Solana addresses.

An optional filter you did not set means "no restriction", and it makes no difference how you say that: leave the field out, send null, or send an empty list. All three behave identically, so a filter list your own code assembled and left empty subscribes to everything instead of failing.

Event ​

json
{
  "op": "event",
  "sub": "tt_1",
  "stream": "token_trades",
  "cursor": "000436312304:000015:0000",
  "data": {}
}
FieldDescription
subSubscription that produced the event
streamStream name
cursorEvent position used for replay after reconnecting
dataStream-specific payload

Unsubscribe ​

json
{ "op": "unsubscribe", "id": 2, "sub": "tt_1" }

The sub value is the id returned by the subscription acknowledgement.

Check the connection ​

json
{ "op": "ping", "id": 3 }

The server replies:

json
{ "op": "pong", "id": 3 }

WebSocket protocol pings are sent as well. The JSON command is useful through proxies that consume protocol-level pings.

Errors and notices ​

Errors include the id of the command that caused them. Notices are asynchronous and usually include the affected sub. See Errors & notices.

Realtime Solana data API