openapi: 3.1.0
info:
contact:
email: backend@cybertinolab.com
name: Cyber team
description: "Surf data API gateway providing typed endpoints for crypto market data, project analytics, social signals, on-chain queries, and more. All endpoints use credit-based billing with per-request rate limiting.\n\n## Parameter Naming Conventions\n\nAll endpoints follow a standardized naming scheme. Use these canonical names when calling the API.\n\n### Asset Identification\n\n| Param | Type | Description | Example |\n|-------|------|-------------|---------|\n| `symbol` | string | Uppercase ticker symbol(s), comma-separated | `BTC`, `ETH,SOL` |\n| `q` | string | Free-text search keyword | `bitcoin` |\n| `id` | string | Surf entity UUID for direct lookup | `550e8400-...` |\n| `address` | string | On-chain contract or wallet address. Also accepts ENS names (e.g. `vitalik.eth`) which resolve automatically. | `0xdead...`, `vitalik.eth` |\n\n### Time & Aggregation\n\n| Param | Type | Description | Example |\n|-------|------|-------------|---------|\n| `time_range` | string or int | Lookback window | `7d`, `30d`, `365d`, `max` |\n| `interval` | string | Candlestick / indicator interval | `1h`, `1d`, `1w` |\n| `granularity` | string | Data aggregation granularity | `day`, `block`, `hour` |\n\n### Filtering & Sorting\n\n| Param | Type | Description | Example |\n|-------|------|-------------|---------|\n| `chain` | string | Blockchain name (canonical long-form only) | `ethereum`, `solana`, `base` |\n| `currency` | string | Quote currency | `usd`, `eur`, `btc` |\n| `metric` | string | Metric name (endpoint-specific enum) | `nupl`, `tvl` |\n| `type` | string | Category selector (endpoint-specific enum) | `us-btc-spot` |\n| `sort` | string | Sort direction | `asc`, `desc` |\n\n### Pagination\n\nAll list endpoints support:\n- `limit` (int, default: 20, max: 100) — results per page\n- `offset` (int, default: 0) — pagination offset\n\n### Supported Chains\n\nUse canonical long-form names only. Short aliases (eth, sol, matic, etc.) are **not accepted**.\n\n| Chain | Value |\n|-------|-------|\n| Ethereum | `ethereum` |\n| Polygon | `polygon` |\n| BNB Chain | `bsc` |\n| Solana | `solana` |\n| Avalanche | `avalanche` |\n| Arbitrum | `arbitrum` |\n| Optimism | `optimism` |\n| Fantom | `fantom` |\n| Base | `base` |\n| Linea | `linea` |\n| Cyber | `cyber` |\n\nNot all chains are available on every endpoint. Check each endpoint's `chain` enum for supported values.\n\n## Authentication\n\nAll data endpoints require a Bearer token in the `Authorization` header:\n\n```\nAuthorization: Bearer <API_KEY>\n```\n\n## Error Responses\n\nAll endpoints return errors in a consistent format:\n\n```json\n{\n \"error\": {\n \"code\": \"FORBIDDEN\",\n \"message\": \"insufficient credits\"\n }\n}\n```\n\n| HTTP Status | Meaning |\n|-------------|---------|\n| `400` | Bad request — invalid or missing parameters |\n| `401` | Unauthorized — missing or invalid API key |\n| `404` | Not found — the requested entity does not exist |\n| `422` | Validation error — parameter value is out of range or invalid |\n| `429` | Rate limited — too many requests, retry after the indicated interval |\n| `502` | Upstream error — a data source is temporarily unavailable |\n\n## Credits\n\nEach API call costs a certain number of credits. The cost is returned in every response under `meta.credits_used`. Check your remaining balance via `GET /v1/me/credit-balance`.\n"
title: Hermod DEX Prediction Market API
version: sha-80d3407
servers:
- url: /
tags:
- description: Track prediction markets on Polymarket and Kalshi. Browse events and markets, view live prices and odds, analyze trading volume and open interest history, inspect individual trades, and discover top-ranked markets by activity.
name: Prediction Market
paths:
/gateway/v1/prediction-market/analytics:
get:
description: 'Trends, top markets, momentum distribution, and per-market momentum signals for prediction markets.
**Platform-wide totals:** Omit `category` to get aggregated volume/OI/market-count across the entire prediction market (Polymarket + Kalshi combined). Use `platform` to filter to one exchange. This is the recommended way to answer questions like "What is Polymarket''s total volume this week?" or "How does Kalshi volume compare to Polymarket?"
**Category drill-down:** Provide `category` to scope all data to one category (e.g. crypto, politics).
Combines volume/OI time series, top markets by open interest, momentum summary (price/volume signal distribution), and per-market momentum signals (price changes, volume direction, whale flows).
**Note on top_markets:** When both `category` and `platform` are omitted, top markets are ranked globally by open interest. Because Polymarket OI is significantly larger than Kalshi OI, the list will skew heavily toward Polymarket. Use `platform` to get per-platform rankings.
**Use `search` instead if** you want to browse/search individual markets.
**Data refresh:** ~5 minutes.'
operationId: prediction-market-analytics
parameters:
- description: Category to analyze. Omit to get platform-wide totals across all categories.
explode: false
in: query
name: category
schema:
description: Category to analyze. Omit to get platform-wide totals across all categories.
enum:
- crypto
- culture
- economics
- financials
- politics
- stem
- sports
type: string
- description: Filter to one platform
explode: false
in: query
name: platform
schema:
description: Filter to one platform
enum:
- polymarket
- kalshi
type: string
- description: 'Window for category trends: `7d`, `30d`, `90d`, `180d`, or `1y`. Bucket size is fixed at 1 day — this endpoint uses `time_range` only and does NOT accept `interval`.'
explode: false
in: query
name: time_range
schema:
default: 30d
description: 'Window for category trends: `7d`, `30d`, `90d`, `180d`, or `1y`. Bucket size is fixed at 1 day — this endpoint uses `time_range` only and does NOT accept `interval`.'
enum:
- 7d
- 30d
- 90d
- 180d
- 1y
type: string
- description: Number of top markets to include
explode: false
in: query
name: top_n
schema:
default: 10
description: Number of top markets to include
format: int64
maximum: 50
minimum: 1
type: integer
- description: Sort field for momentum markets
explode: false
in: query
name: sort_by
schema:
default: volume_7d
description: Sort field for momentum markets
enum:
- volume_7d
- whale_flow_net_7d
- price_change_7d
- oi_change_7d
type: string
- description: Sort direction
explode: false
in: query
name: order
schema:
default: desc
description: Sort direction
enum:
- asc
- desc
type: string
- description: Limit for momentum markets list
explode: false
in: query
name: limit
schema:
default: 20
description: Limit for momentum markets list
format: int64
maximum: 100
minimum: 1
type: integer
- description: Pagination offset for momentum markets
explode: false
in: query
name: offset
schema:
default: 0
description: Pagination offset for momentum markets
format: int64
minimum: 0
type: integer
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DataObjectResponseAnalyticsBody'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Prediction Market Analytics
tags:
- Prediction Market
/gateway/v1/prediction-market/correlations:
get:
description: 'Returns 30-day Pearson price correlation pairs between Polymarket markets within a category.
Correlation data covers the top 100 markets by 7-day volume globally; lower-volume markets may not have correlation data.
Filter by `condition_id` to find all markets correlated with a specific market, or set `min_correlation` to control the threshold.
The `category` parameter is required.
**Data refresh:** ~5 minutes.'
operationId: prediction-market-correlations
parameters:
- description: Category (correlations are within-category only)
explode: false
in: query
name: category
required: true
schema:
description: Category (correlations are within-category only)
enum:
- crypto
- culture
- economics
- financials
- politics
- stem
- sports
type: string
- description: Filter to pairs involving this market
explode: false
in: query
name: condition_id
schema:
description: Filter to pairs involving this market
type: string
- description: Minimum absolute correlation
explode: false
in: query
name: min_correlation
schema:
default: 0.5
description: Minimum absolute correlation
format: double
type: number
- description: Results per page
explode: false
in: query
name: limit
schema:
default: 20
description: Results per page
format: int64
maximum: 100
minimum: 1
type: integer
- description: Pagination offset
explode: false
in: query
name: offset
schema:
default: 0
description: Pagination offset
format: int64
minimum: 0
type: integer
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DataResponseCorrelationItem'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Market Correlations
tags:
- Prediction Market
/gateway/v1/prediction-market/kalshi/events:
get:
description: 'Returns Kalshi events with nested markets, optionally filtered by `event_ticker`.
Each event includes market count and a list of markets.
**Data refresh:** ~30 minutes'
operationId: kalshi-events
parameters:
- description: Event ticker identifier. When omitted, returns top active events by volume. Use GET /v1/search/kalshi?q={keyword} to discover valid tickers.
explode: false
in: query
name: event_ticker
schema:
description: Event ticker identifier. When omitted, returns top active events by volume. Use GET /v1/search/kalshi?q={keyword} to discover valid tickers.
examples:
- KXBTC2026250-27JAN01
type: string
- description: Results per page
explode: false
in: query
name: limit
schema:
default: 20
description: Results per page
examples:
- 20
format: int64
maximum: 100
minimum: 1
type: integer
- description: Pagination offset
explode: false
in: query
name: offset
schema:
default: 0
description: Pagination offset
examples:
- 0
format: int64
minimum: 0
type: integer
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DataResponseKalshiEvent'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Kalshi Events
tags:
- Prediction Market
/gateway/v1/prediction-market/kalshi/markets:
get:
description: 'Returns Kalshi markets, optionally filtered by `market_ticker`.
Each market includes price, volume, and status.
**Data refresh:** ~30 minutes'
operationId: kalshi-markets
parameters:
- description: Market ticker identifier. When omitted, returns top active markets by volume. Use GET /v1/search/kalshi?q={keyword} to discover valid tickers.
explode: false
in: query
name: market_ticker
schema:
description: Market ticker identifier. When omitted, returns top active markets by volume. Use GET /v1/search/kalshi?q={keyword} to discover valid tickers.
examples:
- KXBTC2026250-27JAN01-250000
type: string
- description: Results per page
explode: false
in: query
name: limit
schema:
default: 20
description: Results per page
examples:
- 20
format: int64
maximum: 100
minimum: 1
type: integer
- description: Pagination offset
explode: false
in: query
name: offset
schema:
default: 0
description: Pagination offset
examples:
- 0
format: int64
minimum: 0
type: integer
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DataResponseKalshiMarketItem'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Kalshi Markets
tags:
- Prediction Market
/gateway/v1/prediction-market/kalshi/open-interest:
get:
description: 'Daily open interest time series for a Kalshi market.
**Data refresh:** ~30 minutes'
operationId: kalshi-open-interest
parameters:
- description: Market ticker identifier. Use GET /v1/prediction-market/kalshi/markets or GET /v1/search/kalshi?q={keyword} to discover valid tickers.
explode: false
in: query
name: ticker
required: true
schema:
description: Market ticker identifier. Use GET /v1/prediction-market/kalshi/markets or GET /v1/search/kalshi?q={keyword} to discover valid tickers.
examples:
- KXBTC2026250-27JAN01-250000
type: string
- description: 'Window of history to return: `7d`, `30d`, `90d`, `180d`, or `1y`. This endpoint uses `time_range` only — it does NOT accept `interval`.'
explode: false
in: query
name: time_range
schema:
default: 30d
description: 'Window of history to return: `7d`, `30d`, `90d`, `180d`, or `1y`. This endpoint uses `time_range` only — it does NOT accept `interval`.'
enum:
- 7d
- 30d
- 90d
- 180d
- 1y
examples:
- 30d
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DataResponseKalshiOIPoint'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Kalshi Open Interest History
tags:
- Prediction Market
/gateway/v1/prediction-market/kalshi/orderbooks:
get:
description: 'Historical orderbook snapshots for a Kalshi market. Returns yes-side bid/ask levels. Timestamps in milliseconds, prices in cents.
Data refresh: ~5 minutes'
operationId: kalshi-orderbooks
parameters:
- description: Kalshi market ticker
explode: false
in: query
name: ticker
required: true
schema:
description: Kalshi market ticker
examples:
- KXCITRINI-28JUL01
type: string
- description: Start time in Unix milliseconds. 0 means 7 days ago.
explode: false
in: query
name: start_time
schema:
description: Start time in Unix milliseconds. 0 means 7 days ago.
format: int64
type: integer
- description: End time in Unix milliseconds. 0 means current time.
explode: false
in: query
name: end_time
schema:
description: End time in Unix milliseconds. 0 means current time.
format: int64
type: integer
- description: Maximum number of snapshots to return
explode: false
in: query
name: limit
schema:
default: 100
description: Maximum number of snapshots to return
format: int64
maximum: 200
minimum: 1
type: integer
- description: Base64 cursor for pagination
explode: false
in: query
name: pagination_key
schema:
description: Base64 cursor for pagination
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/V2KalshiOrderbooksResponse'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Kalshi Orderbook History
tags:
- Prediction Market
/gateway/v1/prediction-market/kalshi/prices:
get:
description: 'Price time series for a Kalshi market with daily or hourly OHLC data, or latest price from recent trades.
**Data refresh:** ~30 minutes'
operationId: kalshi-prices
parameters:
- description: Market ticker identifier. Use GET /v1/prediction-market/kalshi/markets or GET /v1/search/kalshi?q={keyword} to discover valid tickers.
explode: false
in: query
name: ticker
required: true
schema:
description: Market ticker identifier. Use GET /v1/prediction-market/kalshi/markets or GET /v1/search/kalshi?q={keyword} to discover valid tickers.
examples:
- KXBTC2026250-27JAN01-250000
type: string
- description: 'Window of history to return: `7d`, `30d`, `90d`, `180d`, or `1y`. Ignored when `interval=latest`. Distinct from `interval` (which sets bucket size within the window).'
explode: false
in: query
name: time_range
schema:
default: 30d
description: 'Window of history to return: `7d`, `30d`, `90d`, `180d`, or `1y`. Ignored when `interval=latest`. Distinct from `interval` (which sets bucket size within the window).'
enum:
- 7d
- 30d
- 90d
- 180d
- 1y
examples:
- 30d
type: string
- description: 'Bucket size for each point in the series: `1h` (hourly OHLC), `1d` (daily OHLC), or `latest` (single most-recent trade price). Distinct from `time_range` (window size).'
explode: false
in: query
name: interval
schema:
default: 1d
description: 'Bucket size for each point in the series: `1h` (hourly OHLC), `1d` (daily OHLC), or `latest` (single most-recent trade price). Distinct from `time_range` (window size).'
enum:
- 1h
- 1d
- latest
examples:
- 1d
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DataResponseKalshiPricePoint'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Kalshi Price History
tags:
- Prediction Market
/gateway/v1/prediction-market/kalshi/trades:
get:
description: 'Returns individual trade records for a Kalshi market.
**Filters:** `taker_side`, `min_contracts`, and date range.
**Sort:** `timestamp` or `num_contracts`.
**Data refresh:** real-time'
operationId: kalshi-trades
parameters:
- description: Market ticker identifier. Use GET /v1/prediction-market/kalshi/markets or GET /v1/search/kalshi?q={keyword} to discover valid tickers.
explode: false
in: query
name: ticker
required: true
schema:
description: Market ticker identifier. Use GET /v1/prediction-market/kalshi/markets or GET /v1/search/kalshi?q={keyword} to discover valid tickers.
examples:
- KXBTC2026250-27JAN01-250000
type: string
- description: 'Filter by taker side: `yes` or `no`'
explode: false
in: query
name: taker_side
schema:
description: 'Filter by taker side: `yes` or `no`'
enum:
- 'yes'
- 'no'
type: string
- description: Minimum notional volume in USD (each contract = $1)
explode: false
in: query
name: min_amount
schema:
description: Minimum notional volume in USD (each contract = $1)
format: int64
minimum: 0
type: integer
- description: Start of time range. Accepts Unix seconds (`1704067200`) or date string (`2024-01-01`)
explode: false
in: query
name: from
schema:
description: Start of time range. Accepts Unix seconds (`1704067200`) or date string (`2024-01-01`)
type: string
- description: End of time range. Accepts Unix seconds (`1706745600`) or date string (`2024-02-01`)
explode: false
in: query
name: to
schema:
description: End of time range. Accepts Unix seconds (`1706745600`) or date string (`2024-02-01`)
type: string
- description: Field to sort results by
explode: false
in: query
name: sort_by
schema:
default: timestamp
description: Field to sort results by
enum:
- timestamp
- notional_volume_usd
examples:
- timestamp
type: string
- description: Sort order
explode: false
in: query
name: order
schema:
default: desc
description: Sort order
enum:
- asc
- desc
examples:
- desc
type: string
- description: Results per page
explode: false
in: query
name: limit
schema:
default: 50
description: Results per page
examples:
- 50
format: int64
maximum: 500
minimum: 1
type: integer
- description: Pagination offset
explode: false
in: query
name: offset
schema:
default: 0
description: Pagination offset
examples:
- 0
format: int64
minimum: 0
type: integer
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DataResponseKalshiTrade'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Kalshi Trades
tags:
- Prediction Market
/gateway/v1/prediction-market/kalshi/volumes:
get:
description: 'Daily trading volume time series for a Kalshi market.
**Data refresh:** ~30 minutes'
operationId: kalshi-volumes
parameters:
- description: Market ticker identifier. Use GET /v1/prediction-market/kalshi/markets or GET /v1/search/kalshi?q={keyword} to discover valid tickers.
explode: false
in: query
name: ticker
required: true
schema:
description: Market ticker identifier. Use GET /v1/prediction-market/kalshi/markets or GET /v1/search/kalshi?q={keyword} to discover valid tickers.
examples:
- KXBTC2026250-27JAN01-250000
type: string
- description: 'Window of history to return: `7d`, `30d`, `90d`, `180d`, or `1y`. This endpoint uses `time_range` only — it does NOT accept `interval`.'
explode: false
in: query
name: time_range
schema:
default: 30d
description: 'Window of history to return: `7d`, `30d`, `90d`, `180d`, or `1y`. This endpoint uses `time_range` only — it does NOT accept `interval`.'
enum:
- 7d
- 30d
- 90d
- 180d
- 1y
examples:
- 30d
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DataResponseKalshiVolumePoint'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Kalshi Volume History
tags:
- Prediction Market
/gateway/v1/prediction-market/matching/daily:
get:
description: 'Returns daily volume and open interest comparison for a specific Polymarket <> Kalshi matched pair.
Both `polymarket_condition_id` and `kalshi_market_ticker` are required. Use `matching-market-pairs` to discover matched pairs first.
**Volume units:** Polymarket = USD, Kalshi = contracts.'
operationId: matching-market-daily
parameters:
- description: Polymarket condition ID
explode: false
in: query
name: polymarket_condition_id
required: true
schema:
description: Polymarket condition ID
examples:
- '0x6fefc0438c7598b23531457c8c60541990d0786bd4bd9dfc3eabc8d95c291092'
type: string
- description: Kalshi market ticker
explode: false
in: query
name: kalshi_market_ticker
required: true
schema:
description: Kalshi market ticker
examples:
- KXBTC2026250-27JAN01-250000
type: string
- description: 'Window of daily data to return: `1d`, `7d`, `30d`, `90d`, `180d`, `1y`, or `all`. Bucket size is fixed at 1 day — this endpoint uses `time_range` only and does NOT accept `interval`.'
explode: false
in: query
name: time_range
schema:
default: 30d
description: 'Window of daily data to return: `1d`, `7d`, `30d`, `90d`, `180d`, `1y`, or `all`. Bucket size is fixed at 1 day — this endpoint uses `time_range` only and does NOT accept `interval`.'
enum:
- 1d
- 7d
- 30d
- 90d
- 180d
- 1y
- all
examples:
- 30d
type: string
- description: Maximum rows
explode: false
in: query
name: limit
schema:
default: 200
description: Maximum rows
examples:
- 200
format: int64
maximum: 10000
minimum: 1
type: integer
- description: Pagination offset
explode: false
in: query
name: offset
schema:
default: 0
description: Pagination offset
examples:
- 0
format: int64
minimum: 0
type: integer
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DataResponseMatchedMarketDailyItem'
description: OK
default:
content:
application/json:
schema:
$ref: '#/components/schemas/DataAPIError'
description: Error
security:
- AccessToken: []
summary: Cross-Platform Daily Comparison (Polymarket <> Kalshi)
tags:
- Prediction Market
/gateway/v1/prediction-market/matching/pairs:
get:
description: 'Cross-platform prediction market pair matcher — finds the same event listed on both Polymarket and Kalshi, with live price spread data. This is prediction-market only (Polymarket and Kalshi). For crypto exchange markets, use `exchange-markets`.
Filter by category, match type, confidence score, or look up a specific market''s cross-platform counterpart via `polymarket_condition_id` or `kalshi_market_ticker`.
Each pair includes current prices and spread percentage for arbitrage analysis. Sort by `spread_pct` to find the widest spreads.
**Data refresh:** ~5 minutes'
operationId: matching-market-pairs
parameters:
- description: Filter by category
explode: false
in: query
name: category
schema:
description: Filter by category
enum:
- crypto
- culture
- economics
- financials
- politics
- stem
- sports
examples:
- politics
type: string
- description: Filter by match type
explode: false
in: query
name: match_type
schema:
description: Filter by match type
enum:
- exact
- related
examples:
- exact
type: string
- description: Only return pairs where both markets are currently active
explode: false
in: query
name: active_only
schema:
default: false
description: Only return pairs where both markets are currently active
type: boolean
- description: Minimum confidence score (0-100)
explode: false
in: query
name: min_confidence
schema:
default: 0
description: Minimum confidence score (0-100)
format: int64
maximum: 100
minimum: 0
type: integer
- description: Find match for this Polymarket market
explode: false
in: query
name: polymarket_condition_id
schema:
description: Find match for this Polymarket market
type: string
- description: Find match for this Kalshi market
explode: false
in: query
name: kalshi_market_ticker
schema:
description: Find match for this Kalshi market
type: string
- description: Sort field
explode: false
in: query
name: sort_by
schema:
default: confidence
description: Sort field
enum:
- confidence
- polymarket_volume
- kalshi_volume
- spread_pct
type: string
- description: Sort order
explode: false
in: query
name: order
schema:
default: desc
description: Sort order
enum:
- asc
- desc
type: string
- description: Maximum rows to return
explode: false
in: query
name: limit
schema:
defa
# --- truncated at 32 KB (115 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/surf/refs/heads/main/openapi/surf-prediction-market-api-openapi.yml