MetaDAO Market data API
Daily volume and fee history from the served ETL.
Daily volume and fee history from the served ETL.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/metadao:metadao-market-data-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Futarchy External Market data API
version: 2.0.0
description: 'Public, read-only HTTP API serving Futarchy protocol DEX data (FutarchyAMM spot markets, plus Meteora pools for daily market data) to aggregators such as CoinGecko, CoinMarketCap, DexScreener and Jupiter, and to dashboards.
**Versioning.** Every data endpoint is served under `/v1` (e.g. `/v1/api/tickers`) and, unchanged, at its unversioned path, which is a frozen alias of v1. Health, probe, metrics and docs endpoints are not versioned. Breaking changes ship as a new version prefix. A deprecated version answers with `Deprecation` (RFC 9745), `Sunset` (RFC 8594) and `Link: ; rel="successor-version"` headers.
**Units.** Token amounts, prices and volumes are in human units (already divided by the mint decimals). Most adapters serve them as decimal strings; fields suffixed `Raw` are integer strings in base units. Adapters whose consumer requires JSON numbers (CoinMarketCap, DexScreener, the Jupiter supply endpoints) serve numbers, as noted per schema.
**Rate limits.** Anonymous clients get 60 requests per minute per IP. Trusted partners send an `X-API-Key` header and get a higher limit; an unknown key is rejected with 401 `INVALID_API_KEY`. Rate-limited responses carry `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (seconds); a 429 also carries `Retry-After` (seconds). Container probes (`/health/startup`, `/health/ready`, `/health/live`) are not rate limited. Limits are enforced across all replicas when the deployment shares a Redis store.
**Caching.** Successful data responses are sent with `Cache-Control: private, max-age=30` (client-side reuse only; responses carry per-caller rate-limit headers). Errors, health and metrics responses are `Cache-Control: no-store`. Responses over 1 KB are compressed (`br`, `gzip` or `deflate`) when the request sends `Accept-Encoding`.
**Serving invariant.** Infrastructure failures (Solana RPC, served database) return a 5xx. The API never answers 200 with zero, empty, or placeholder financial data because a dependency failed. Retry on 5xx; treat a 200 as authoritative.
**Errors.** Every error is JSON in one shape, the `Error` schema: `{ error, code, field?, requestId }`. Branch on `code` (stable), not on the `error` message (human-readable, may change); `field` names the offending parameter on a 400. Each request may take each query parameter at most once: a repeated parameter is a 400 `INVALID_QUERY_PARAMETER`. Unknown routes return 404 `NOT_FOUND`. A request that exceeds the server timeout returns 503 `REQUEST_TIMEOUT`.'
servers:
- url: /
tags:
- name: Market Data
description: Daily volume and fee history from the served ETL.
paths:
/api/market-data:
servers:
- url: /v1
description: Versioned (recommended for new integrations)
- url: /
description: Unversioned alias of v1, kept for existing integrations
get:
operationId: getMarketData
summary: Daily market data
description: Daily FutarchyAMM (spot, conditional and total) and Meteora activity per token over an inclusive date range. Parameters are validated before the database is touched, so a bad request is always 400.
tags:
- Market Data
security:
- {}
- apiKey: []
parameters:
- name: startDate
in: query
required: true
description: First UTC day, inclusive (YYYY-MM-DD). Must be a real calendar date on or before `endDate`.
schema:
type: string
format: date
pattern: ^\d{4}-\d{2}-\d{2}$
example: '2026-01-01'
- name: endDate
in: query
required: true
description: Last UTC day, inclusive (YYYY-MM-DD). The range may span at most 366 days (server default); split longer histories into several requests.
schema:
type: string
format: date
pattern: ^\d{4}-\d{2}-\d{2}$
example: '2026-01-31'
- name: tokens
in: query
required: false
description: Comma-separated base-token mints to filter by (at most 100, each a valid Solana address). Omit for all tokens.
schema:
type: string
responses:
'200':
description: Daily market data.
headers:
Cache-Control:
$ref: '#/components/headers/CacheControlPublic'
RateLimit-Limit:
$ref: '#/components/headers/RateLimitLimit'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimitRemaining'
RateLimit-Reset:
$ref: '#/components/headers/RateLimitReset'
X-Request-Id:
$ref: '#/components/headers/XRequestId'
content:
application/json:
schema:
$ref: '#/components/schemas/MarketDataResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalError'
'503':
$ref: '#/components/responses/ServiceUnavailable'
components:
headers:
RetryAfter:
description: Seconds to wait before retrying.
schema:
type: integer
CacheControlNoStore:
description: '`no-store` on errors, health and metrics responses.'
schema:
type: string
const: no-store
RateLimitRemaining:
description: Requests remaining in the current window.
schema:
type: integer
RateLimitReset:
description: Seconds until the current window resets.
schema:
type: integer
RateLimitLimit:
description: Requests allowed per window for this client tier.
schema:
type: integer
XRequestId:
description: Request id (echoes a safe client-supplied `X-Request-Id`, otherwise a generated UUID). Quote it when reporting problems.
schema:
type: string
CacheControlPublic:
description: '`private, max-age=30` on successful data responses.'
schema:
type: string
examples:
- private, max-age=30
schemas:
MeteoraDailyVolume:
type: object
description: One token-day of Meteora activity. Decimal strings in human units.
required:
- token
- date
- base_volume
- target_volume
- buy_volume
- sell_volume
- trade_count
- average_price
- usdc_fees
- token_fees
- token_fees_usdc
- token_per_usdc
properties:
token:
type: string
pattern: ^[1-9A-HJ-NP-Za-km-z]{32,44}$
description: Base token mint.
examples:
- So11111111111111111111111111111111111111112
date:
type: string
format: date
base_volume:
type: string
description: Volume in the base token. Decimal string in human units.
examples:
- '1234.56'
target_volume:
type: string
description: Volume in USDC. Decimal string in human units.
examples:
- '1234.56'
buy_volume:
type: string
description: Buy-side volume. Decimal string in human units.
examples:
- '1234.56'
sell_volume:
type: string
description: Sell-side volume. Decimal string in human units.
examples:
- '1234.56'
trade_count:
type: integer
average_price:
type: string
description: Average price (USDC per token). Decimal string in human units.
examples:
- '1234.56'
usdc_fees:
type: string
description: Fees in USDC. Decimal string in human units.
examples:
- '1234.56'
token_fees:
type: string
description: Fees in the base token. Decimal string in human units.
examples:
- '1234.56'
token_fees_usdc:
type: string
description: Base-token fees valued in USDC. Decimal string in human units.
examples:
- '1234.56'
token_per_usdc:
type:
- string
- 'null'
description: base_volume / target_volume; null when target_volume is 0.
MarketDataResponse:
type: object
required:
- filters
- source
- futarchyAMM
- meteora
properties:
filters:
type: object
required:
- tokens
- startDate
- endDate
properties:
tokens:
description: The requested token list, or the string "all" when no filter was given.
oneOf:
- type: string
const: all
- type: array
items:
type: string
startDate:
type: string
format: date
endDate:
type: string
format: date
source:
type: string
const: user-pool-etl
futarchyAMM:
type: object
required:
- source
- count
- data
properties:
source:
type: string
const: etl-user-pool-daily
count:
type: integer
data:
type: array
items:
$ref: '#/components/schemas/FutarchyAmmDailyActivity'
meteora:
type: object
required:
- source
- count
- data
properties:
source:
type: string
const: etl-meteora-daily
count:
type: integer
data:
type: array
items:
$ref: '#/components/schemas/MeteoraDailyVolume'
Error:
type: object
description: The error body of every endpoint.
required:
- error
- code
- requestId
properties:
error:
type: string
description: Human-readable message. May change; branch on `code`.
code:
type: string
description: Stable machine-readable code.
examples:
- NOT_FOUND
- RATE_LIMITED
- INVALID_API_KEY
- INVALID_QUERY_PARAMETER
- INVALID_MINT_ADDRESS
- SERVED_DB_UNAVAILABLE
- SERVED_DATA_STALE
- REQUEST_TIMEOUT
- INTERNAL_ERROR
field:
type: string
description: 'On a 400: the request parameter that was rejected.'
examples:
- startDate
- id
requestId:
type: string
description: Request id, same as the `X-Request-Id` header.
FutarchyAmmDailyActivity:
type: object
description: 'One token-day of FutarchyAMM activity: spot, conditional (null when absent) and totals. Volumes are USD / human token units as decimal strings.'
required:
- token
- date
- has_conditional_volume
- spot_buy_volume
- spot_sell_volume
- spot_base_volume
- spot_target_volume
- spot_usdc_fees
- spot_token_fees
- spot_token_fees_usdc
- spot_protocol_fee_usd
- spot_lp_fee_usd
- spot_trade_count
- conditional_buy_volume
- conditional_sell_volume
- conditional_base_volume
- conditional_target_volume
- conditional_usdc_fees
- conditional_token_fees
- conditional_token_fees_usdc
- conditional_protocol_fee_usd
- conditional_lp_fee_usd
- conditional_trade_count
- total_buy_volume
- total_sell_volume
- total_base_volume
- total_target_volume
- total_usdc_fees
- total_token_fees
- total_token_fees_usdc
- total_protocol_fee_usd
- total_lp_fee_usd
- total_trade_count
- conditional_reconciled
- pending_open_proposals
properties:
token:
type: string
pattern: ^[1-9A-HJ-NP-Za-km-z]{32,44}$
description: Base token mint.
examples:
- So11111111111111111111111111111111111111112
date:
type: string
format: date
description: UTC day (YYYY-MM-DD).
has_conditional_volume:
type: boolean
description: True when the day has a conditional-market row.
spot_buy_volume:
type: string
description: 'Spot market: Buy-side volume (quote/USD). Decimal string in human units.'
examples:
- '1234.56'
spot_sell_volume:
type: string
description: 'Spot market: Sell-side volume (quote/USD). Decimal string in human units.'
examples:
- '1234.56'
spot_base_volume:
type: string
description: 'Spot market: Volume in the base token. Decimal string in human units.'
examples:
- '1234.56'
spot_target_volume:
type: string
description: 'Spot market: Volume in the quote token (USD). Decimal string in human units.'
examples:
- '1234.56'
spot_usdc_fees:
type: string
description: 'Spot market: Fees collected in USDC. Decimal string in human units.'
examples:
- '1234.56'
spot_token_fees:
type: string
description: 'Spot market: Fees collected in the base token. Decimal string in human units.'
examples:
- '1234.56'
spot_token_fees_usdc:
type: string
description: 'Spot market: Base-token fees valued in USDC. Decimal string in human units.'
examples:
- '1234.56'
spot_protocol_fee_usd:
type: string
description: 'Spot market: Protocol fee portion (USD), collected to the treasury. Decimal string in human units.'
examples:
- '1234.56'
spot_lp_fee_usd:
type: string
description: 'Spot market: LP fee portion (USD), retained in the pool. Decimal string in human units.'
examples:
- '1234.56'
spot_trade_count:
type: integer
description: Spot market trade count.
conditional_buy_volume:
type:
- string
- 'null'
description: 'Conditional markets: Buy-side volume (quote/USD). Decimal string in human units; null when the day had no conditional-market row.'
conditional_sell_volume:
type:
- string
- 'null'
description: 'Conditional markets: Sell-side volume (quote/USD). Decimal string in human units; null when the day had no conditional-market row.'
conditional_base_volume:
type:
- string
- 'null'
description: 'Conditional markets: Volume in the base token. Decimal string in human units; null when the day had no conditional-market row.'
conditional_target_volume:
type:
- string
- 'null'
description: 'Conditional markets: Volume in the quote token (USD). Decimal string in human units; null when the day had no conditional-market row.'
conditional_usdc_fees:
type:
- string
- 'null'
description: 'Conditional markets: Fees collected in USDC. Decimal string in human units; null when the day had no conditional-market row.'
conditional_token_fees:
type:
- string
- 'null'
description: 'Conditional markets: Fees collected in the base token. Decimal string in human units; null when the day had no conditional-market row.'
conditional_token_fees_usdc:
type:
- string
- 'null'
description: 'Conditional markets: Base-token fees valued in USDC. Decimal string in human units; null when the day had no conditional-market row.'
conditional_protocol_fee_usd:
type:
- string
- 'null'
description: 'Conditional markets: Protocol fee portion (USD), collected to the treasury. Decimal string in human units; null when the day had no conditional-market row.'
conditional_lp_fee_usd:
type:
- string
- 'null'
description: 'Conditional markets: LP fee portion (USD), retained in the pool. Decimal string in human units; null when the day had no conditional-market row.'
conditional_trade_count:
type:
- integer
- 'null'
description: Conditional markets trade count; null when the day had no conditional-market row.
total_buy_volume:
type: string
description: 'Spot + conditional: Buy-side volume (quote/USD). Decimal string in human units.'
examples:
- '1234.56'
total_sell_volume:
type: string
description: 'Spot + conditional: Sell-side volume (quote/USD). Decimal string in human units.'
examples:
- '1234.56'
total_base_volume:
type: string
description: 'Spot + conditional: Volume in the base token. Decimal string in human units.'
examples:
- '1234.56'
total_target_volume:
type: string
description: 'Spot + conditional: Volume in the quote token (USD). Decimal string in human units.'
examples:
- '1234.56'
total_usdc_fees:
type: string
description: 'Spot + conditional: Fees collected in USDC. Decimal string in human units.'
examples:
- '1234.56'
total_token_fees:
type: string
description: 'Spot + conditional: Fees collected in the base token. Decimal string in human units.'
examples:
- '1234.56'
total_token_fees_usdc:
type: string
description: 'Spot + conditional: Base-token fees valued in USDC. Decimal string in human units.'
examples:
- '1234.56'
total_protocol_fee_usd:
type: string
description: 'Spot + conditional: Protocol fee portion (USD), collected to the treasury. Decimal string in human units.'
examples:
- '1234.56'
total_lp_fee_usd:
type: string
description: 'Spot + conditional: LP fee portion (USD), retained in the pool. Decimal string in human units.'
examples:
- '1234.56'
total_trade_count:
type: integer
description: Spot + conditional trade count.
conditional_reconciled:
type: boolean
description: Whether conditional volume for the day has been reconciled.
pending_open_proposals:
type: integer
description: Open proposals whose conditional volume is still pending.
responses:
ServiceUnavailable:
description: A dependency is unavailable or its data is stale (e.g. `SERVED_DB_UNAVAILABLE`, `SERVED_DATA_STALE`) or the request timed out (`REQUEST_TIMEOUT`). Retry later.
headers:
Cache-Control:
$ref: '#/components/headers/CacheControlNoStore'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
BadRequest:
description: 'Invalid request: `INVALID_MINT_ADDRESS` for a bad path address, `INVALID_QUERY_PARAMETER` for a missing, malformed or repeated query parameter. `field` names the parameter.'
headers:
Cache-Control:
$ref: '#/components/headers/CacheControlNoStore'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Unknown `X-API-Key` (`INVALID_API_KEY`), or missing/invalid metrics bearer token on `/metrics`.
headers:
Cache-Control:
$ref: '#/components/headers/CacheControlNoStore'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
InternalError:
description: Unexpected server or upstream (RPC/DB) failure. Retry later.
headers:
Cache-Control:
$ref: '#/components/headers/CacheControlNoStore'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
TooManyRequests:
description: Rate limit exceeded (`RATE_LIMITED`).
headers:
Cache-Control:
$ref: '#/components/headers/CacheControlNoStore'
RateLimit-Limit:
$ref: '#/components/headers/RateLimitLimit'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimitRemaining'
RateLimit-Reset:
$ref: '#/components/headers/RateLimitReset'
Retry-After:
$ref: '#/components/headers/RetryAfter'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
securitySchemes:
apiKey:
type: apiKey
in: header
name: X-API-Key
description: Optional partner key. Requests without it are served at the anonymous rate limit (60/min per IP); a valid key gets the trusted limit; an unknown key is rejected with 401 `INVALID_API_KEY`.
metricsBearer:
type: http
scheme: bearer
description: Required on `/metrics` only when the server sets `METRICS_TOKEN`; the token is that value. When `METRICS_TOKEN` is unset, `/metrics` is open.