API Documentation

Everything you need to integrate Cashmere into your application. Prediction market data from every platform through a single API.

Base URL: https://api.cashmerelabs.xyz

Quick Start

Install the SDK, initialize the client with your API key, and start querying markets.

Install
npm install @cashmere/sdk
example.ts
import { CashmereClient } from "@cashmere/sdk"

const cashmere = new CashmereClient({
  apiKey: "vk_live_..."
})

const { data } = await cashmere.getMarkets({
  sort: "volume",
  limit: 10,
})

Authentication

All endpoints except /v1/health require an API key passed via the x-api-key header.

x-api-keyheaderrequired

Your API key. Recommended method.

api_keyquery

Alternative: pass as query parameter.

Header (recommended)
curl -H "x-api-key: YOUR_API_KEY" \
  https://api.cashmerelabs.xyz/v1/markets
GET/v1/markets

List Markets

List markets across all platforms with filtering, sorting, and pagination.

platformstring

"polymarket", "kalshi", "opinion", "predict", "forecastex", "overtime", "myriad". Omit for all.

querystring

Full-text search query string.

statusstring

"active", "closed", or "resolved".

categorystring

Filter by category slug.

sortstring

"volume", "liquidity", "newest", or "ending_soon".

limitnumber

Results per page (1-100, default 20).

cursorstring

Pagination cursor from previous response.

curl -X GET "https://api.cashmerelabs.xyz/v1/markets?platform=polymarket&sort=volume&limit=5" \
  -H "x-api-key: YOUR_API_KEY"
Response200
{
  "data": [
    {
      "id": "polymarket:0x1234...",
      "platform": "polymarket",
      "platformMarketId": "0x1234...",
      "platformUrl": "https://polymarket.com/event/...",
      "title": "Will X happen by Y?",
      "description": "...",
      "probability": 0.65,
      "outcomes": [
        { "name": "Yes", "probability": 0.65 },
        { "name": "No", "probability": 0.35 }
      ],
      "volume": 1250000,
      "volumeCurrency": "USDC",
      "liquidity": 85000,
      "status": "active",
      "createdAt": "2025-01-15T00:00:00Z",
      "endDate": "2025-12-31T00:00:00Z",
      "lastUpdatedAt": "2025-06-20T12:34:56Z"
    }
  ],
  "count": 5,
  "nextCursor": "5"
}
GET/v1/markets/:id

Get Market

Get a single market by its Cashmere ID. The ID format is {platform}:{platformMarketId}, for example kalshi:BTC-100K-2025.

curl -X GET "https://api.cashmerelabs.xyz/v1/markets/polymarket:0x1234" \
  -H "x-api-key: YOUR_API_KEY"
Response200
{
  "data": {
    "id": "polymarket:0x1234...",
    "platform": "polymarket",
    "title": "Will X happen by Y?",
    "probability": 0.65,
    "volume": 1250000,
    "status": "active"
  }
}
GET/v1/orderbooks/:marketId

Get Orderbook

Get the unified orderbook for a market. Aggregates depth from Polymarket and Kalshi.

curl -X GET "https://api.cashmerelabs.xyz/v1/orderbooks/polymarket:0x1234" \
  -H "x-api-key: YOUR_API_KEY"
Response200
{
  "data": {
    "marketId": "polymarket:0x1234",
    "platform": "polymarket",
    "bids": [
      { "price": 0.62, "size": 500 },
      { "price": 0.61, "size": 1200 }
    ],
    "asks": [
      { "price": 0.64, "size": 800 },
      { "price": 0.65, "size": 300 }
    ],
    "spread": 0.02,
    "midpoint": 0.63,
    "lastUpdatedAt": "2025-06-20T12:34:56Z"
  }
}
GET/v1/candles/:marketId

Get Candles

Get OHLC candlestick data for a market. Useful for charting price history.

intervalstring

"1m", "5m", "15m", "1h", "4h", "1d". Default "1h".

startstring

ISO 8601 start time.

endstring

ISO 8601 end time.

limitnumber

Max candles to return (1-1000, default 100).

curl -X GET "https://api.cashmerelabs.xyz/v1/candles/polymarket:0x1234?interval=1h&limit=24" \
  -H "x-api-key: YOUR_API_KEY"
Response200
{
  "data": [
    {
      "timestamp": "2025-06-20T12:00:00Z",
      "open": 0.62,
      "high": 0.68,
      "low": 0.61,
      "close": 0.65,
      "volume": 12400
    }
  ],
  "count": 24
}
GET/v1/alerts

List Alerts

List all alerts configured for the authenticated API key.

curl -X GET "https://api.cashmerelabs.xyz/v1/alerts" \
  -H "x-api-key: YOUR_API_KEY"
Response200
{
  "data": [
    {
      "id": "alert_01",
      "marketId": "polymarket:0x1234",
      "condition": { "type": "price_above", "threshold": 0.8 },
      "delivery": { "type": "webhook", "url": "https://..." },
      "status": "active",
      "createdAt": "2025-06-20T10:00:00Z"
    }
  ]
}
POST/v1/alerts

Create Alert

Create a new alert with a condition and delivery configuration. Fires when the condition is met.

marketIdstringrequired

The Cashmere market ID to monitor.

condition.typestringrequired

"price_above", "price_below", "price_change", "volume_spike", or "market_resolved".

condition.thresholdnumber

Threshold value for price conditions.

condition.percentChangenumber

Percentage change for price_change alerts.

condition.windowMsnumber

Time window in milliseconds.

delivery.typestringrequired

"webhook" or "websocket".

delivery.urlstring

Webhook URL (required for webhook delivery).

delivery.headersobject

Optional headers to include in webhook requests.

curl -X POST "https://api.cashmerelabs.xyz/v1/alerts" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "marketId": "polymarket:0x1234",
    "condition": { "type": "price_above", "threshold": 0.8 },
    "delivery": { "type": "webhook", "url": "https://your-server.com/hook" }
  }'
Response201
{
  "data": {
    "id": "alert_02",
    "marketId": "polymarket:0x1234",
    "condition": { "type": "price_above", "threshold": 0.8 },
    "delivery": { "type": "webhook", "url": "https://your-server.com/hook" },
    "status": "active",
    "createdAt": "2025-06-20T12:00:00Z"
  }
}
DELETE/v1/alerts/:id

Delete Alert

Delete an alert by its ID. Returns 204 on success.

curl -X DELETE "https://api.cashmerelabs.xyz/v1/alerts/alert_02" \
  -H "x-api-key: YOUR_API_KEY"
GET/v1/portfolio

Get Portfolio

Get aggregated cross-platform positions. Requires platform API keys configured server-side.

curl -X GET "https://api.cashmerelabs.xyz/v1/portfolio" \
  -H "x-api-key: YOUR_API_KEY"
Response200
{
  "data": {
    "positions": [...],
    "totalValue": 5240.50,
    "totalPnl": 340.20,
    "byPlatform": {
      "polymarket": { "positions": [...], "value": 3200, "pnl": 200 },
      "kalshi": { "positions": [...], "value": 2040.50, "pnl": 140.20 }
    }
  }
}
GET/v1/wallets

List Wallets

List connected wallet addresses and their balances across platforms.

curl -X GET "https://api.cashmerelabs.xyz/v1/wallets" \
  -H "x-api-key: YOUR_API_KEY"
Response200
{
  "data": [
    {
      "platform": "polymarket",
      "address": "0xabc...",
      "balance": 1250.00,
      "currency": "USDC"
    }
  ]
}

WebSocket

Connect to wss://api.cashmerelabs.xyz/v1/ws and subscribe to real-time channels.

market:updatedchannel

Fires when market data changes.

market:newchannel

Fires when a new market is listed.

market:resolvedchannel

Fires when a market resolves.

orderbook:updatedchannel

Fires on orderbook depth changes.

price:changedchannel

Fires on price movement.

*channel

Subscribe to all channels.

Subscribe
{"action": "subscribe", "channel": "price:changed"}
{"action": "subscribe", "channel": "orderbook:updated"}
Incoming event
{
  "type": "event",
  "channel": "price:changed",
  "data": {
    "marketId": "polymarket:0x123",
    "platform": "polymarket",
    "oldPrice": 0.65,
    "newPrice": 0.68
  }
}
GET/v1/stream

Server-Sent Events

Lightweight alternative to WebSocket. Pass channels as a comma-separated query parameter, or omit for all events.

channelsstring

Comma-separated channel names to subscribe to.

Terminal
curl -N -H "x-api-key: vk_live_..." \
  "https://api.cashmerelabs.xyz/v1/stream?channels=price:changed,orderbook:updated"

TypeScript SDK

The official SDK provides typed methods for every endpoint plus async iterator streaming.

Every REST endpoint has a corresponding SDK method with full TypeScript types.

Streaming uses async iterators — for await over real-time events.

Usage
import { CashmereClient } from "@cashmere/sdk"

const cashmere = new CashmereClient({ apiKey: "vk_live_..." })

// Markets
const markets = await cashmere.getMarkets({ sort: "volume" })

// Alerts
await cashmere.createAlert({
  marketId: "polymarket:0x1234",
  condition: { type: "price_above", threshold: 0.9 },
  delivery: { type: "webhook", url: "https://..." },
})

// Streaming (async iterator)
for await (const event of cashmere.stream(["price:changed"])) {
  console.log(event.channel, event.data)
}

Error Handling

All errors return JSON with an error field and the appropriate HTTP status code.

400Bad Request

Invalid query parameters or request body.

401Unauthorized

Missing API key.

403Forbidden

Invalid API key.

404Not Found

Resource not found.

429Too Many Requests

Rate limit exceeded. Check Retry-After header.

500Server Error

Internal server error.

Error response429
{ "error": "Rate limit exceeded." }
SDK error handling
import { CashmereRateLimitError } from "@cashmere/sdk"

try {
  await cashmere.getMarkets()
} catch (err) {
  if (err instanceof CashmereRateLimitError) {
    console.log("Retry after", err.retryAfter, "s")
  }
}

Rate Limits

Rate limits are applied per API key using a sliding window. Headers are included in every response.

TierRateStreaming
Free1 req/sec1 connection
Pro100 req/sec10 connections
EnterpriseUnlimitedUnlimited
X-RateLimit-LimitX-RateLimit-RemainingRetry-After