Polymarket Market Data API & MCP Server

Four REST endpoints and a hosted MCP server over the same data set: 28 Polymarket up/down markets (7 assets × 4 timeframes), tick-level, 90 days of history. Requires a Premium plan. Base URL https://www.updowncharts.com. See what an up/down market is for the underlying market mechanics.

Authentication

Create a key at /dashboard/settings (shown once, prefix udc_). Send it as a Bearer token on every request. The key resolves to a user, the user resolves to a tier, and the tier must be Premium — keys held by Free or Pro accounts authenticate but are rejected with 403.

curl -H "Authorization: Bearer udc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  https://www.updowncharts.com/api/v1/markets

Revoking a key at any time invalidates it immediately. Every authenticated request updates the key's last_used_at.

Rate limits & errors

Premium keys are limited to 100 requests per minute and 50,000 requests per day, counted per key. Successful responses carry X-RateLimit-Remaining-Minute and X-RateLimit-Remaining-Day.

StatusBodyWhen
400{"error":"invalid_market","code":400}Unknown asset or timeframe.
400{"error":"invalid_slug","code":400}Slug does not match the canonical pattern.
401{"error":"invalid_key","code":401}Missing, malformed, revoked or unknown key.
403{"error":"api_requires_premium","code":403}Valid key on a Free or Pro account.
404{"error":"not_found","code":404}No data for that slug or market.
429{"error":"rate_limited","code":429}Minute or day quota exhausted. Retry-After holds the seconds left in the current minute window.

GET /api/v1/markets

Returns the full catalog of 28 markets plus the tier your key resolves to. The catalog is static configuration, so this endpoint is the cheapest way to discover valid asset and timeframe values before calling anything else. The same catalog is browsable at /markets.

{
  "markets": [
    {
      "key": "btc-5m",
      "asset": "btc",
      "symbol": "BTC",
      "displayName": "Bitcoin",
      "timeframe": "5m",
      "durationSeconds": 300,
      "label": "5M"
    },
    {
      "key": "btc-15m",
      "asset": "btc",
      "symbol": "BTC",
      "displayName": "Bitcoin",
      "timeframe": "15m",
      "durationSeconds": 900,
      "label": "15M"
    }
  ],
  "tier": "premium"
}

Takes no parameters. Errors: 401, 403, 429.

GET /api/v1/epochs

Paginated epoch history for one market, newest first. Each row is one settled or open window with its price to beat, close, outcome and final volume. Pagination is keyset based on the epoch number: pass the returned nextCursor back as cursor to get the next page. nextCursor is null on the last page.

NameTypeRequiredDefaultDescription
assetstringnobtcbtc, eth, sol, xrp, doge, bnb, hype. An unrecognised value returns 400 invalid_market.
timeframestringno15m5m, 15m, 1h, 4h. An unrecognised value returns 400 invalid_market.
datestring (YYYY-MM-DD)noall datesRestrict to one calendar date.
limitintegerno100Rows per page. Clamped to 1000; non-numeric or non-positive values fall back to 100.
cursorstring (epoch)nonewestReturn only epochs strictly older than this epoch number.
curl -H "Authorization: Bearer udc_..." \
  "https://www.updowncharts.com/api/v1/epochs?asset=btc&timeframe=15m&limit=50"

{
  "epochs": [
    {
      "slug": "btc-updown-15m-1751000400",
      "date": "2026-06-27",
      "outcome": "UP",
      "ptb": 107412.5,
      "close": 107480.1,
      "volume": 18422.36,
      "hasTickPrices": true,
      "polymarketSlug": "btc-updown-15m-1751000400"
    },
    {
      "slug": "btc-updown-15m-1750999500",
      "date": "2026-06-27",
      "outcome": "DOWN",
      "ptb": 107455.0,
      "close": 107412.5,
      "volume": 20117.02,
      "hasTickPrices": true,
      "polymarketSlug": null
    }
  ],
  "nextCursor": "1750999500"
}

Errors: 400 invalid_market, 401, 403, 429.

GET /api/v1/ticks/{slug}

Full tick series for one epoch, returned column-wise: every array is the same length and index i across all arrays describes the same tick. Timestamps in ts are offsets in milliseconds from baseTs. Missing values are null rather than interpolated. If the epoch is the current live one and no recorded rows exist yet, the live buffer is returned instead.

NameTypeRequiredDefaultDescription
slugstring (path)yesCanonical slug {asset}-updown-{timeframe}-{epoch}, epoch exactly 10 digits.
curl -H "Authorization: Bearer udc_..." \
  https://www.updowncharts.com/api/v1/ticks/btc-updown-15m-1751000400

{
  "slug": "btc-updown-15m-1751000400",
  "date": "2026-06-27",
  "outcome": "UP",
  "ptb": 107412.5,
  "close": 107480.1,
  "baseTs": 1751000400000,
  "ticks": {
    "ts":          [0, 412, 907],
    "upBid":       [0.49, 0.51, 0.53],
    "upAsk":       [0.51, 0.53, 0.55],
    "downBid":     [0.47, 0.45, 0.43],
    "downAsk":     [0.51, 0.49, 0.47],
    "binance":     [107412.5, 107419.8, 107433.1],
    "chainlink":   [107410.0, null, 107431.7],
    "pyth":        [107413.2, 107420.4, 107434.0],
    "ptbCaptured": [107412.5, 107412.5, 107412.5],
    "ptbApi":      [null, 107412.5, 107412.5]
  }
}

Errors: 400 invalid_slug, 404 not_found (no data, including epochs older than the 90-day retention window), 401, 403, 429.

GET /api/v1/live/{asset}/{timeframe}

Latest single snapshot for the market's current epoch: most recent underlying prices, most recent top-of-book quotes, and the price to beat. ts is the newer of the two source timestamps in Unix milliseconds. The slug is derived server-side from the current wall clock, so no epoch argument is needed.

NameTypeRequiredDefaultDescription
assetstring (path)yesbtc, eth, sol, xrp, doge, bnb, hype.
timeframestring (path)yes5m, 15m, 1h, 4h.
curl -H "Authorization: Bearer udc_..." \
  https://www.updowncharts.com/api/v1/live/btc/15m

{
  "slug": "btc-updown-15m-1751000400",
  "ts": 1751000812345,
  "binance": 107419.8,
  "chainlink": 107418.0,
  "pyth": 107420.4,
  "upBid": 0.51,
  "upAsk": 0.53,
  "downBid": 0.45,
  "downAsk": 0.49,
  "ptb": 107412.5
}

Errors: 400 invalid_market, 404 not_found (no tick or quote rows yet for the current epoch), 401, 403, 429.

MCP server

A hosted Model Context Protocol server at https://www.updowncharts.com/api/mcp. Transport is Streamable HTTP and the server is stateless — every request carries the same udc_ Bearer key and is authorized before it reaches the tool layer, so the 401 / 403 / 429 responses above apply identically. GET, POST and DELETE are handled.

claude mcp add --transport http updown https://www.updowncharts.com/api/mcp --header "Authorization: Bearer udc_..."
ToolArgumentsReturns
list_marketsnoneReturns { markets: [...] } — the same catalog as GET /api/v1/markets.
get_epochsasset (string), timeframe (string), date (string, optional), limit (number, optional, default 100, max 1000)Epochs newest-first for one market. No cursor argument — the tool always starts from the newest epoch.
get_ticksslug (string)Full tick arrays for one epoch slug.
get_live_priceasset (string), timeframe (string)Latest snapshot for the current epoch of that market.
get_epoch_summaryslug (string)Outcome, ptb, close and volume for one epoch slug.

Tool results are JSON encoded as text content, matching the REST response shapes above. An unknown market or missing slug comes back as an error result (isError), not an HTTP error.

Field glossary

FieldMeaning
slugCanonical market identifier: {asset}-updown-{timeframe}-{epoch}, e.g. btc-updown-15m-1751000000. Assets and timeframes come from the catalog; epoch is exactly 10 digits.
epochUnix second at which the window opened, floored to the timeframe duration (300 / 900 / 3600 / 14400 s). The window ends at epoch + durationSeconds.
ptbPrice to beat — the open price of the window. Close above it resolves UP; a tie resolves DOWN. ptbCaptured is our own capture at window open; ptbApi is Polymarket’s (delayed) reported value.
closeFinal crypto price for the window, used together with ptb to derive outcome.
outcome"UP", "DOWN", or null while the epoch is still open or unresolved.
upBid / upAsk / downBid / downAskTop-of-book Polymarket CLOB quotes for the UP and DOWN outcome tokens, in probability terms (0–1). null when no quote was recorded.
binance / chainlink / pythUnderlying spot price from each source at that tick. null where a source does not cover the asset (HYPE has no Binance or Chainlink series).
volumeFinal market volume in USD, read from Polymarket at resolution. null until resolved.
hasTickPricestrue when tick-level rows exist for the epoch, so /api/v1/ticks/{slug} will return series data.
polymarketSlugPolymarket’s own slug for the market. Identical to the canonical slug for 5m, 15m and 4h; 1h markets use an ET date slug instead (e.g. bitcoin-up-or-down-july-9-2026-10am-et). null when not yet recorded.

Retention & data access by tier

Tick and quote tables are monthly partitions with a 90-day retention window; partitions older than 90 days are dropped daily. Epoch summaries and tick series outside that window return 404. Export what you need to keep.

TierMarketsHistoryAPI / MCP
FreeBTC 15mLive epoch onlyNo
ProAll 28Full 90 days + CSV + WebSocketNo
PremiumAll 28Full 90 days + CSV + WebSocketREST + MCP, 100/min, 50,000/day

Compare plans →