---
title: "OHLCV candles for a token"
method: GET
path: "/tokens/{mint}/candles"
tags: ["Tokens"]
---

# OHLCV candles for a token

`GET /tokens/{mint}/candles`

## Request

- Base URL: `https://madeonsol.com/api/v1`
- URL: `https://madeonsol.com/api/v1/tokens/{mint}/candles`
- Auth: HTTP bearer

Open/high/low/close + volume candles aggregated from the 1-minute base series. PRO gets all timeframes with the last 30 days of history measured from now (`history_floor`): a window entirely older returns 200 with zero candles and `history_outside_plan: true`, a partly older one is clamped (`history_clamped: true`). ULTRA (and BUSINESS) adds net-flow/liquidity fields and full retained history. This tier split applies to Solana candles only; RHC candles are full-history on PRO+. Candles are read newest-first in grid-aligned database windows that start small and grow while reads are fast; each request has a time budget of about five seconds. When the time budget runs out (typically a dense token over closed months on cold storage) the default answer is 503 `read_budget_exhausted` with `covered_from` and Retry-After; with `partial=allow` the newest complete candles read so far are returned with `truncated: true` and `covered_from` (continue with `to=covered_from`). Never a partial candle.

## Path parameters

- `mint` string, required

## Query parameters

- `tf` '1m' | '5m' | '15m' | '1h' | '4h' | '1d'
- `limit` integer
- `from` string, date-time
- `to` string, date-time
- `partial` 'allow'

## Response `200`

OK

- object
  - `mint` string
  - `timeframe` '1m' | '5m' | '15m' | '1h' | '4h' | '1d'
  - `from` string, date-time
  - `to` string, date-time
  - `count` integer
  - `net_flow_included` boolean: true on ULTRA — signals whether the net-flow/liquidity fields below are present
  - `truncated` boolean: true when the read stopped before `limit` candles or `from` were reached: the per-request call cap (always), or the time budget (only with partial=allow; otherwise 503). The returned candles are complete; `covered_from` is the oldest instant searched, so request older candles with `to=covered_from`.
  - `covered_from` string, date-time: Oldest instant actually searched; equals `from` when the whole window was scanned
  - `history_floor` string, date-time, nullable: PRO: now minus 30 days, rounded up to the tf grid (oldest bucket served). null on ULTRA/BUSINESS (no floor)
  - `history_clamped` boolean: PRO: part of the requested window was older than history_floor and was cut; `from` echoes the clamped start
  - `history_outside_plan` boolean: PRO: the whole requested window is older than history_floor, so 200 with zero candles
  - `candles` object[]
    - `t` string: Bucket start (ISO timestamp as returned by the OHLC rollup)
    - `open` number, nullable
    - `high` number, nullable
    - `low` number, nullable
    - `close` number, nullable
    - `volume_usd` number, nullable
    - `trades` integer, nullable
    - `market_cap_usd` number, nullable
    - `buy_volume_usd` number, nullable: ULTRA only
    - `sell_volume_usd` number, nullable: ULTRA only
    - `net_volume_usd` number, nullable: ULTRA only — buy_volume_usd − sell_volume_usd
    - `buy_count` integer, nullable: ULTRA only
    - `sell_count` integer, nullable: ULTRA only
    - `volume_mev_usd` number, nullable: ULTRA only
    - `open_liquidity_usd` number, nullable: ULTRA only
    - `close_liquidity_usd` number, nullable: ULTRA only
    - `high_mc_usd` number, nullable: ULTRA only
    - `low_mc_usd` number, nullable: ULTRA only

## Other responses

- `400`: Invalid tf/limit/window
- `401`: Missing or invalid API key, or an expired free-tier key. Authentication-stage error: no `X-RateLimit-*` headers, no `_rid`.
- `403`: Forbidden. One of: the key's tier is below this endpoint's or parameter's gate (`tier_required` with an `upgrade` block); the public demo key used outside its allow-list (`demo_key_endpoint_not_allowed`); an invalid or revoked key; an origin-restricted key called from a disallowed origin (`code` `origin_not_allowed` / `origin_required`). `X-RateLimit-*` headers are present only on `tier_required`.
- `429`: Too many requests. Every 429 carries `Retry-After`. A quota 429 (`rate_limit_exceeded`, with `X-RateLimit-*`), a heavy-query concurrency 429 (`error_kind` `concurrency`/`capacity`), or the per-IP authentication-failure block (30 failed auths/min; plain `error` + `retry_after_seconds`, no `X-RateLimit-*`).
- `500`: Unexpected server error from the route (`Internal server error`, with `_rid`). Safe to retry with backoff. A failed API-key lookup is a 503 `auth_backend_unavailable`, never a 500.
- `503`: error_kind=read_budget_exhausted: the read budget ran out before the window was read and partial=allow was not set. Body carries covered_from and retry_after_seconds; Retry-After header set. Also statement_timeout (error_kind=statement_timeout) when not even one bucket could be read.

---

[API](https://skmtc.dev/madeonsol/apis/madeonsol-api.md) · [All operations](https://skmtc.dev/madeonsol/apis/madeonsol-api/llms.txt) · [OpenAPI document](https://skmtc.dev/madeonsol/apis/madeonsol-api/revisions/96ce84657f55?raw)
