GRAPHQL

One endpoint. Two root fields.

Candles for a Solana pool with only the fields you select, plus the venue list. Introspection is on, so you will size this schema yourself within a minute of arriving. There are no mutations, no subscriptions and no nested graph, and it is better that you hear that here.

Root fields
2
Candle fields
15
Timeframes
8
Candles
146M+
Pipelinelive · public demo stream

Validator to your transport.

Connecting
0 frames this session
Inspector
Hover or focus a node to hold the flow and read what is passing through it. Every value comes from the last swap this page received.
feed
connecting
frames this session
0
events decoded
read live on /products
last venue
Query console

Drop a field. Watch the payload shrink.

A real query against the public endpoint, run while this page was rendered. Every control is a link, so changing the pool, the timeframe or the selection set re-runs it server-side, no client JavaScript is involved, and the byte count on the request line is the measured size of the data block that came back.

POST/graphql200132 ms11545 B of data
Request body
query Candles($pair: String!, $tf: String!, $start: String, $n: Int) {
  candles(pairAddress: $pair, timeframe: $tf, start: $start, limit: $n) {
    timestamp
    open
    high
    low
    close
    volumeSol
    tradeCount
  }
}

// variables
{
  "pair": "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE",
  "tf": "1m",
  "start": "2026-09-16T12:29:00+00:00",
  "n": 60
}
Response · first 2 of 60
{
  "data": {
    "candles": [
      {
        "timestamp": "2026-09-16T12:29:00+00:00",
        "open": 0.010260701065015901,
        "high": 0.010263231357866562,
        "low": 0.010253268167993376,
        "close": 0.010255008123196315,
        "volumeSol": 284781834553,
        "tradeCount": 31
      },
      {
        "timestamp": "2026-09-16T12:30:00+00:00",
        "open": 0.010255008123196315,
        "high": 0.010276911582199936,
        "low": 0.010255008123196315,
        "close": 0.010268684612366104,
        "volumeSol": 1514782469410,
        "tradeCount": 72
      }
    ]
  }
}
The returned rows, drawn2026-09-16T12:29:00+00:002026-09-16T13:28:00+00:00
0.01030.01030.01030.01030.0103
Surface

The entire schema, printed.

Not an excerpt. This is what __schema returns today, transcribed field for field.

SDL · from introspection
schema {
  query: QueryRoot
}

type QueryRoot {
  candles(
    pairAddress: String!
    timeframe: String!
    start: String
    end: String
    limit: Int
  ): [GqlCandle!]!

  protocols: [String!]!
}

type GqlCandle {
  timestamp: String!
  pairAddress: String!
  tokenAddress: String!
  baseMint: String!
  timeframe: String!
  open: Float!
  high: Float!
  low: Float!
  close: Float!
  volumeSol: Float!
  volumeToken: Float!
  tradeCount: Int!
  buyCount: Int!
  sellCount: Int!
  uniqueTraders: Int!
}

# No Mutation type. No Subscription type.
# __schema returns null for both.
HTTP surface
  • POST/graphqlQueries and introspection: the entire GraphQL surface
  • GET/graphqlA stub page that links back to POST. Not a GraphiQL IDE
  • GET/api/v1/candles/latestREST only: GraphQL has no newest-first field
  • GET/api/v1/protocolsREST equivalent of the protocols field
{ protocols } · the whole field
pumpfunpumpswapraydium_ammraydium_clmmraydium_cpmmorcameteora_damm_v2meteora_dbcmeteora_dlmmmeteora_pools

10 venue ids. No arguments, no sub-selection, no pagination. Asking for it returns all of it. That is the second of the two root fields, in its entirety.

GqlCandle · every field
  • timestampString!

    ISO-8601 with a +00:00 offset, not a Z suffix

  • pairAddressString!

    The pool you asked for, echoed back

  • tokenAddressString!

    The token side of the pool

  • baseMintString!

    The mint the price is denominated in

  • timeframeString!

    Echoed back; one of the eight

  • openFloat!

    Base mint per token, already decimal-adjusted

  • highFloat!

    Highest trade in the bucket

  • lowFloat!

    Lowest trade in the bucket

  • closeFloat!

    Last trade in the bucket

  • volumeSolFloat!

    Lamports despite the name: divide by 1e9

  • volumeTokenFloat!

    Base units: divide by 10^decimals

  • tradeCountInt!

    Trades in the bucket

  • buyCountInt!

    Direction resolved per venue

  • sellCountInt!

    Direction resolved per venue

  • uniqueTradersInt!

    Distinct wallets in the bucket

Worth knowing

Four things that will cost you an afternoon.

limit returns the oldest rows

There is no latest field. The resolver counts forward from start, which defaults to the beginning of the pool’s history, so limit: 5 on its own hands you the five oldest candles in the index, and end does not anchor it the other way. Pass a recent start; the console above does, and shows you the value it used.

errors arrive with a 200

An unknown field or a bad timeframe comes back as HTTP 200 with data: null and an errors array. A status code will not tell you the query failed. A missing or rejected key is a 401, because that is the transport answering rather than the resolver. So branch on the body, not on res.ok.

units

volumeSol is lamports, not SOL: divide by 1e9. volumeToken is base units. Prices are already decimal-adjusted, so no decimals lookup is needed, and timestamp carries a +00:00 offset rather than a Z.

nothing streams here

Introspection returns null for both the mutation and the subscription root, so GraphQL is a request/response surface over candle history. For real-time WebSocket streaming or decoded swaps, use the other transports. And GET /graphql serves a stub page linking back to POST, not a GraphiQL IDE. Point your own client at the endpoint and introspect it.

Other transports

Need newest-first, or live?

REST has the newest-first candle endpoint this schema lacks, the same candles stream over WebSocket, and every decoded swap has its own feed.

Pipeline

One query, the same decoded corpus.

  1. 01

    Validators

    Transactions execute on the Solana cluster.

  2. 02

    Yellowstone Geyser

    Transaction updates stream off the node.

  3. 03

    Dexploit engine

    Decoded across 10 protocols into one record.

  4. 04

    GraphQL resolver

    You select the fields; only those are assembled and returned.

Plans

Rate limits, stated per second.

Starterentry
$0
Rate
20 RPS
History
Full history
Support
Community
Developer
$50/mo
Rate
100 RPS
Connections
10 concurrent
History
Full history
Support
Email
Pro
$199/mo
Rate
500 RPS
Connections
50 concurrent
History
Full history
Support
Priority

Limits are per second. The plans have no monthly request quota, so none is quoted here.