heromarket.com/api/v1

Hero Market API v1

Public read-only JSON API for Hero Market. CORS-open, no key required. Anyone can curl these endpoints from a terminal, a notebook, or the browser console. The Hero Market embed widget and any third-party analytics tool consume this same surface.

Conventions

Quick start

# List the 5 most-traded active markets
curl -s 'https://heromarket.com/api/v1/markets?limit=5'

# Pull one market in full
curl -s 'https://heromarket.com/api/v1/markets/olipop-jan-2026'

# Top 25 traders by Brier calibration this month, insiders only
curl -s 'https://heromarket.com/api/v1/leaderboard?scope=insider&period=month&metric=brier'

Endpoints

  1. GET/api/v1/markets

    List markets. Default sort is 24-hour volume descending. Returns summary fields per market.

    Query params

    NameTypeDescription
    statusstringactive (default), closed, resolved, all. Filter by market status.
    categorystringFilter by category slug, e.g. functional_beverage.
    limitinteger1 to 100. Default 50.
    offsetintegerPagination cursor. Pass meta.next_offset from the previous response.

    Example response

    {
      "data": [
        {
          "slug": "olipop-jan-2026",
          "title": "Will OLIPOP launch a new flavor in January 2026?",
          "category": "functional_beverage",
          "status": "active",
          "price_yes": 0.62,
          "price_no": 0.38,
          "closes_at": "2026-01-31T23:59:59Z",
          "resolves_by": "2026-02-07T23:59:59Z",
          "resolved_at": null,
          "created_at": "2026-05-01T12:00:00Z"
        }
      ],
      "meta": {
        "version": "1",
        "generated_at": "2026-05-16T03:00:00Z",
        "rate_limit_remaining": 59,
        "next_offset": 50,
        "total": 87
      }
    }
  2. GET/api/v1/markets/{slug}

    Single market detail. Includes description, resolution criteria, pools, total volume, comment count, holder count.

    Example response

    {
      "data": {
        "slug": "olipop-jan-2026",
        "title": "Will OLIPOP launch a new flavor in January 2026?",
        "category": "functional_beverage",
        "status": "active",
        "description": "OLIPOP announces a new SKU on or before Jan 31, 2026.",
        "resolution_criteria": "OLIPOP publicly announces a new SKU on their site, press release, or official social on or before Jan 31, 2026.",
        "resolution_source": "https://drinkolipop.com/blogs/news",
        "price_yes": 0.62,
        "price_no": 0.38,
        "pool_yes": 482.5,
        "pool_no": 783.2,
        "total_volume": 14250.0,
        "comment_count": 23,
        "holder_count": 41,
        "closes_at": "2026-01-31T23:59:59Z",
        "resolves_by": "2026-02-07T23:59:59Z",
        "resolved_at": null,
        "created_at": "2026-05-01T12:00:00Z"
      },
      "meta": { "version": "1", "generated_at": "...", "rate_limit_remaining": 58 }
    }
  3. GET/api/v1/markets/{slug}/prices

    Price history, downsampled to ~250 points. Returns an array of (t, price_yes) pairs.

    Query params

    NameTypeDescription
    periodstring1h, 6h, 1d (default), 1w, all.

    Example response

    {
      "data": [
        { "t": "2026-05-16T01:30:00Z", "price_yes": 0.58 },
        { "t": "2026-05-16T02:30:00Z", "price_yes": 0.61 },
        { "t": "2026-05-16T03:00:00Z", "price_yes": 0.62 }
      ],
      "meta": { "version": "1", "generated_at": "...", "rate_limit_remaining": 57 }
    }
  4. GET/api/v1/markets/{slug}/trades

    Recent trades for the market, newest first. Handles only.

    Query params

    NameTypeDescription
    limitinteger1 to 500. Default 100.

    Example response

    {
      "data": [
        {
          "created_at": "2026-05-16T02:58:12Z",
          "user_handle": "freshfridge",
          "side": "yes",
          "shares": 12.5,
          "cost": 7.75,
          "price_yes": 0.62
        }
      ],
      "meta": { "version": "1", "generated_at": "...", "rate_limit_remaining": 56 }
    }
  5. GET/api/v1/leaderboard

    Sliceable leaderboard. Same axes as heromarket.com/leaderboard.

    Query params

    NameTypeDescription
    scopestringall (default), insider, consumer, category.
    categorystringRequired when scope=category.
    periodstringtoday, week, month, all (default).
    metricstringprofit (default), brier, winrate, volume.
    limitinteger1 to 100. Default 25.

    Example response

    {
      "data": [
        {
          "handle": "freshfridge",
          "display_name": "Fresh Fridge",
          "tier": "insider",
          "profit": 1240.5,
          "volume": null,
          "brier": 0.17,
          "win_rate": 0.71,
          "markets_resolved": 42,
          "wins": 30,
          "losses": 12
        }
      ],
      "meta": { "version": "1", "generated_at": "...", "rate_limit_remaining": 55 }
    }
  6. GET/api/v1/categories

    Active categories with the count of active markets in each.

    Example response

    {
      "data": [
        { "slug": "functional_beverage", "name": "Functional Beverage", "market_count": 20 }
      ],
      "meta": { "version": "1", "generated_at": "...", "rate_limit_remaining": 54 }
    }
  7. GET/api/v1/accuracy

    Platform calibration numbers: average Brier, top-decile Brier, and accuracy decay by trade horizon.

    Example response

    {
      "data": {
        "platform_brier": 0.21,
        "top_decile_brier": 0.12,
        "markets_resolved": 384,
        "by_horizon": [
          { "horizon_days_max": 7,  "brier": 0.16, "markets_resolved": 110 },
          { "horizon_days_max": 30, "brier": 0.21, "markets_resolved": 180 },
          { "horizon_days_max": 90, "brier": 0.27, "markets_resolved": 94  }
        ]
      },
      "meta": { "version": "1", "generated_at": "...", "rate_limit_remaining": 53 }
    }

Errors

Errors return a non-2xx HTTP status and a JSON body of the shape:

{ "error": "rate_limited", "retry_after_seconds": 42 }