Bidweave API

Cross-platform prediction market data infrastructure. Bidweave ingests markets from Polymarket and Kalshi, normalizes them into canonical events via embedding similarity and LLM validation, and exposes a unified API for querying events, prices, and linked news.

Base URL

https://swarm-1gnx.onrender.com

Key Concepts

Events are cross-platform normalized groupings of markets about the same topic. Each event has a consensus price, total volume, and linked markets from both Polymarket and Kalshi.

Markets are raw prediction markets from individual platforms, with bid/ask/spread data and price snapshots.

Quick Example
# Get top events by volume
curl /api/events?limit=5&status=active

# Search by topic
curl -X POST /api/markets/search \
  -H "Content-Type: application/json" \
  -d '{"text": "bitcoin price"}'

Authentication

Most read endpoints are public and require no authentication. The /api/query/* endpoints require an API key.

API Key

Pass your key via the X-Api-Key header. Keys are rate-limited to 60 requests per minute.

X-Api-Key header Your API key (required for /api/query/* endpoints only)
Authenticated Request
curl /api/query/search \
  -H "X-Api-Key: your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"text": "federal reserve"}'

GET /api/events

List canonical events with optional filters. Returns paginated results sorted by total volume (default).

Query Parameters

limit integer Max results (default: 200, max: 500)
offset integer Pagination offset (default: 0)
status string "active" or "resolved" (default: all)
category string Filter by category (e.g. "Politics", "Sports")
min_volume number Minimum total volume filter
sort_by string "volume", "title", "odds", "markets", "updated" (default: "volume")
sort_dir string "asc" or "desc" (default: "desc")
Request
curl /api/events?limit=2&status=active&sort_by=volume
Response
{
  "events": [
    {
      "id": 42,
      "title": "Will Bitcoin exceed $100k in 2025?",
      "category": "Crypto",
      "category_group": "Crypto",
      "consensus_price": 0.72,
      "market_count": 3,
      "total_volume": 1250000,
      "updated_at": "2025-03-15T12:00:00Z"
    }
  ],
  "total": 156,
  "limit": 2,
  "offset": 0
}

GET /api/events/{id}

Get a single canonical event with all linked markets and their latest prices.

Path Parameters

id integer Required Event ID
Request
curl /api/events/42
Response
{
  "id": 42,
  "title": "Will Bitcoin exceed $100k in 2025?",
  "category": "Crypto",
  "category_group": "Crypto",
  "consensus_price": 0.72,
  "market_count": 3,
  "total_volume": 1250000,
  "markets": [
    {
      "platform": "polymarket",
      "title": "Bitcoin above $100k?",
      "mid_price": 0.73,
      "last_price": 0.73,
      "yes_bid": 0.72,
      "yes_ask": 0.74,
      "spread": 0.02,
      "volume": 850000,
      "volume_24h": 45000,
      "open_interest": null,
      "floor_strike": null,
      "strike_type": null,
      "category_group": "Crypto",
      "event_id": 42
    }
  ]
}

GET /api/events/{id}/price-history

Get price history for all markets in an event. Returns time-series snapshots for each linked market.

Path Parameters

id integer Required Event ID
Request
curl /api/events/42/price-history
Response
{
  "event_id": 42,
  "markets": [
    {
      "market_id": 101,
      "platform": "polymarket",
      "title": "Bitcoin above $100k?",
      "snapshots": [
        {
          "captured_at": "2025-03-15T12:00:00Z",
          "mid_price": 0.73,
          "volume": 850000
        }
      ]
    }
  ]
}

GET /api/events/{id}/articles

Get news articles linked to an event, grouped by story cluster with novelty scores. Also returns a flat articles array for backwards compatibility.

Path Parameters

id integer Required Event ID

Query Parameters

limit integer Max articles (default: 20)
offset integer Pagination offset (default: 0)

Story Object

cluster_id integer Story cluster ID
title string Cluster representative title
summary string Human-readable summary: single title or top 3 article titles joined by " | "
novelty_score number 0-1 novelty score (higher = more novel)
similarity number 256-dim cosine similarity to event
similarity_3072 number 3072-dim cosine similarity to event
first_seen string Earliest article timestamp in cluster
source_count integer Number of source articles in cluster
articles array Source articles: { id, title, url, source, published_at }
Request
curl /api/events/42/articles
Response
{
  "event_id": 42,
  "stories": [
    {
      "cluster_id": 1205,
      "title": "Bitcoin Rally Continues...",
      "summary": "Bitcoin Rally Continues...",
      "novelty_score": 0.85,
      "similarity": 0.82,
      "similarity_3072": 0.91,
      "first_seen": "2025-03-14T08:30:00Z",
      "source_count": 3,
      "articles": [
        {
          "id": 501,
          "title": "Bitcoin Rally Continues...",
          "url": "https://example.com/article",
          "source": "Reuters",
          "published_at": "2025-03-14"
        }
      ]
    }
  ],
  "articles": [
    {
      "id": 501,
      "title": "Bitcoin Rally Continues...",
      "url": "https://example.com/article",
      "source": "Reuters",
      "similarity": 0.82,
      "published_at": "2025-03-14"
    }
  ]
}

GET /api/events/{id}/timeline

Chronological story flow for an event, ordered by first_seen. Shows how the narrative around an event has evolved over time.

Path Parameters

id integer Required Event ID

Query Parameters

limit integer Max entries (default: 50)
offset integer Pagination offset (default: 0)
Request
curl /api/events/42/timeline
Response
{
  "event_id": 42,
  "event_title": "Will Bitcoin exceed $100k in 2025?",
  "timeline": [
    {
      "cluster_id": 1205,
      "title": "Bitcoin Rally Continues...",
      "novelty_score": 0.85,
      "similarity": 0.82,
      "similarity_3072": 0.91,
      "source_count": 3,
      "first_seen": "2025-03-14T08:30:00Z",
      "last_seen": "2025-03-14T14:00:00Z"
    }
  ]
}

GET /api/stories/recent

Recent high-novelty stories linked to any event. Use this to discover breaking news and novel developments across all tracked events.

Query Parameters

min_novelty number Minimum novelty score (default: 0.0)
hours integer Lookback window in hours (default: 48)
limit integer Max results (default: 50)
offset integer Pagination offset (default: 0)
Request
curl /api/stories/recent?min_novelty=0.7&hours=24&limit=10
Response
{
  "stories": [
    {
      "cluster_id": 1205,
      "title": "Bitcoin Rally Continues...",
      "summary": "Bitcoin Rally Continues...",
      "source_count": 3,
      "first_seen": "2025-03-14T08:30:00Z",
      "last_seen": "2025-03-14T14:00:00Z",
      "event_id": 42,
      "event_title": "Will Bitcoin exceed $100k?",
      "similarity": 0.82,
      "similarity_3072": 0.91,
      "novelty_score": 0.85
    }
  ]
}

GET /api/events/{id}/matches

Get cross-platform matched market pairs for an event. Shows which Polymarket and Kalshi markets were matched by embedding similarity and LLM validation.

Path Parameters

id integer Required Event ID
Request
curl /api/events/42/matches
Response
{
  "event_id": 42,
  "pairs": [
    {
      "market_a": {
        "id": 101,
        "platform": "polymarket",
        "title": "Bitcoin above $100k by June?",
        "mid_price": 0.73,
        "volume": 850000
      },
      "market_b": {
        "id": 205,
        "platform": "kalshi",
        "title": "Will Bitcoin exceed $100,000?",
        "mid_price": 0.71,
        "volume": 620000
      },
      "sim_256": 0.89,
      "sim_3072": 0.94,
      "llm_verdict": "MATCH",
      "validated_at": "2025-03-14T12:00:00Z"
    }
  ],
  "count": 1
}

GET /api/markets

List raw markets from Polymarket and Kalshi with optional filters.

Query Parameters

limit integer Max results (default: 200, max: 500)
offset integer Pagination offset (default: 0)
platform string "polymarket" or "kalshi"
status string "active" or "resolved"
min_volume number Minimum volume filter
max_volume number Maximum volume filter
min_spread number Minimum spread filter
price_min number Minimum mid_price
price_max number Maximum mid_price
min_days_to_resolution integer Min days until close_time
max_days_to_resolution integer Max days until close_time
sort_by string "volume", "volume_24h", "title", "price", "spread", "updated" (default: "volume")
sort_dir string "asc" or "desc" (default: "desc")
Request
curl /api/markets?platform=polymarket&limit=5&sort_by=spread&sort_dir=asc
Response
{
  "markets": [
    {
      "id": 101,
      "platform": "polymarket",
      "title": "Bitcoin above $100k?",
      "mid_price": 0.73,
      "last_price": 0.73,
      "spread": 0.02,
      "volume": 850000,
      "volume_24h": 45000,
      "open_interest": null,
      "floor_strike": null,
      "strike_type": null,
      "status": "active",
      "category": "crypto",
      "category_group": "Crypto",
      "event_id": 42,
      "resolved_outcome": null,
      "resolved_at": null,
      "final_price": null,
      "resolution_criteria": "Resolves Yes if...",
      "rules_secondary": null
    }
  ],
  "total": 1240,
  "limit": 5,
  "offset": 0
}

GET /api/markets/{platform}/{platform_id}

Get a single market by platform and platform-specific ID.

Path Parameters

platform string Required "polymarket" or "kalshi"
platform_id string Required Platform-specific market identifier
Request
curl /api/markets/polymarket/0x1234abcd
Response
{
  "id": 101,
  "platform": "polymarket",
  "platform_id": "0x1234abcd",
  "title": "Bitcoin above $100k?",
  "mid_price": 0.73,
  "last_price": 0.73,
  "yes_bid": 0.72,
  "yes_ask": 0.74,
  "spread": 0.02,
  "volume": 850000,
  "volume_24h": 45000,
  "open_interest": null,
  "floor_strike": null,
  "strike_type": null,
  "category_group": "Crypto",
  "event_id": 42,
  "event": {
    "id": 42,
    "title": "Will Bitcoin exceed $100k?"
  }
}

GET /api/markets/{market_id}/price-history

Get price snapshots for a single market by database ID.

Path Parameters

market_id integer Required Market database ID

Query Parameters

hours integer Lookback window in hours (default: 168 / 7 days)
Request
curl /api/markets/101/price-history?hours=72
Response
{
  "market_id": 101,
  "snapshots": [
    {
      "captured_at": "2025-03-15T12:00:00Z",
      "mid_price": 0.73,
      "yes_bid": 0.72,
      "yes_ask": 0.74,
      "spread": 0.02,
      "volume": 850000,
      "volume_delta": 1200
    }
  ]
}

POST /api/markets/price-history/batch

Get price snapshots for multiple markets in one request. Accepts up to 1000 market IDs. Resolved markets return their last 1000 snapshots; active markets filter by the hours lookback window.

Body Parameters

market_ids integer[] Required Array of market database IDs (max 1000)
hours integer Lookback window in hours (default: 168 / 7 days)
Request
curl -X POST /api/markets/price-history/batch \
  -H "Content-Type: application/json" \
  -d '{"market_ids": [101, 205, 312], "hours": 72}'
Response
{
  "markets": [
    {
      "market_id": 101,
      "snapshots": [
        {
          "captured_at": "2025-03-15T12:00:00Z",
          "mid_price": 0.73,
          "yes_bid": 0.72,
          "yes_ask": 0.74,
          "spread": 0.02,
          "volume": 850000,
          "volume_delta": 1200
        }
      ]
    },
    {
      "market_id": 205,
      "snapshots": [...]
    }
  ]
}

POST /api/markets/batch

Get current data for multiple markets in one request. Useful for exit checking and position monitoring without per-market API calls. Max 1000 IDs.

Body Parameters

market_ids integer[] Required Array of market database IDs (max 1000)
Request
curl -X POST /api/markets/batch \
  -H "Content-Type: application/json" \
  -d '{"market_ids": [101, 205, 312]}'
Response
{
  "markets": [
    {
      "id": 101,
      "platform": "polymarket",
      "title": "Will BTC exceed $100k by June?",
      "mid_price": 0.73,
      "status": "active",
      "resolved_outcome": null,
      "volume": 850000,
      "event_id": 42
    }
  ]
}

GET /api/matches

Get all cross-platform matched market pairs. Returns MATCH-validated pairs with computed price spread. Replaces per-event match lookups.

Query Parameters

min_volume number Min volume on either market (default: 0)
min_spread number Min cross-platform price spread
status string "active" or "resolved" (both sides must match)
limit integer Max results (default: 200, max: 500)
offset integer Pagination offset (default: 0)
Request
curl /api/matches?min_volume=50000&status=active
Response
{
  "pairs": [
    {
      "market_a": {
        "id": 101,
        "platform": "polymarket",
        "title": "BTC above $100k by June?",
        "mid_price": 0.73,
        "volume": 850000,
        "status": "active",
        "event_id": 42
      },
      "market_b": {
        "id": 205,
        "platform": "kalshi",
        "title": "Bitcoin above $100,000 by June 30?",
        "mid_price": 0.68,
        "volume": 120000,
        "status": "active",
        "event_id": 42
      },
      "sim_3072": 0.96,
      "llm_verdict": "MATCH",
      "spread": 0.05
    }
  ],
  "total": 234,
  "limit": 200,
  "offset": 0
}

Errors

The API uses standard HTTP status codes. Error responses include a detail message.

400 Bad request — invalid parameters
401 Unauthorized — missing or invalid API key
404 Not found — resource does not exist
429 Rate limited — too many requests (60/min)
500 Internal server error
Error Response
{
  "detail": "Event not found"
}

Python SDK

Install the Bidweave Python SDK for typed access to all endpoints.

Installation

pip install bidweave

Quick Start

The SDK provides async and sync clients with automatic pagination, type hints, and error handling.

Python SDK
# pip install bidweave
from bidweave import Bidweave

client = Bidweave(base_url="https://swarm-1gnx.onrender.com")

# List active events
events = client.events(status="active", limit=10)
for ev in events:
    print(f"{ev.title}: {ev.consensus_price:.0%}")

# Search markets
results = client.search("bitcoin price")
for r in results:
    print(f"[{r.platform}] {r.title} ({r.similarity:.2f})")

# Get price history
history = client.event_prices(event_id=42)
for market in history:
    print(f"{market.platform}: {len(market.snapshots)} points")