# Markets

**Beta, early access.** These endpoints are open to selected accounts while they're tested, and may still change. `/v0/matches` is unchanged and stays the way to get Kalshi ↔ one-venue matches.

A **Layer market** is one real-world question, like "Velez Sarsfield beat Union Santa Fe on Nov 6", with every venue's market for it side by side. Each venue's market is a **listing**.

`/v0/matches` gives you Kalshi and one other venue per item, one venue per request. `/v0/markets` gives you every venue in one item.

## Reading a market

Every answer below is a real one. Five things to look at:

1. **`question`**: the real-world question, in plain words. It's left out when a venue on the market doesn't allow Layer to show its wording, as on every market that includes polymarket.com (see [All fields](#all-fields)).
2. **`listings`**: one per venue that lists it, each with its `venue`, `market_id` and `url`.
3. **`basis`** on each listing: `identical` means the same bet. `equivalent_with_caveats` means the same question with a rule difference, named in `caveats` (such as `rounding_differs`). Keep only `identical` listings and you always have the same bet.
4. **`price`** on each listing: the venue's live best `bid` and `ask` for YES and NO, with sizes.
5. **`best_trade`**: the best "buy YES on one venue, NO on another" between identical listings, with fees. `best_trade_any` is the same between any two listings, rule differences included.

## GET /v0/markets

Open markets listed on two or more venues that haven't ended, soonest first: by `start_time` for markets starting later or in the last 4 hours, else by `event_time` (a season-long market sorts by when it settles).

```
curl -H "Authorization: Bearer $LAYER_API_KEY" "https://uselayer.sh/v0/markets?category=crypto&from=2026-11-06&limit=1&prices=false"
```

```json
{
  "count": 1,
  "markets": [
    {
      "id": "lyr_0117c14f6267",
      "event_id": "lyr_evt_185a779da3e5",
      "category": "crypto",
      "question": "ETH at or above $2,960 at 5 PM ET, Nov 6",
      "event_time": "2026-11-06T22:05:00.000Z",
      "status": "open",
      "listings": [
        {
          "venue": "kalshi",
          "market_id": "KXETHD-26NOV0617-T2959.99",
          "url": "https://kalshi.com/markets/kxethd/x/kxethd-26nov0617",
          "series": "KXETHD",
          "basis": "identical",
          "caveats": [],
          "reference": true,
          "question": "Ethereum price at Nov 6, 2026 at 5pm EST?",
          "outcome": "$2,960 or above"
        },
        {
          "venue": "polymarket_us",
          "market_id": "cpceth-eth-above-wk-2026-11-06-2960",
          "url": "https://polymarket.us/event/eth-above-wk-2026-11-06",
          "series": "eth-strike-weekly",
          "basis": "equivalent_with_caveats",
          "caveats": ["rounding_differs"],
          "question": "ETH Price at 5:00PM ET on Fri, Nov 6",
          "outcome": "$2,960 or above"
        }
      ]
    }
  ],
  "attribution": "Market data from Kalshi (kalshi.com) and Polymarket US (polymarket.us). Each market's url links to its page on the venue, where it's traded."
}
```

Here Kalshi is the **reference** listing, and Polymarket US is the same question with one difference: the two venues round the price differently.

| Query | Default | Meaning |
|---|---|---|
| `category` | all | `sports`, `crypto`, `politics`, `economics`, … |
| `q` | none | Words that must all appear: `q=nfl`, `q=bitcoin`. |
| `from` | not ended yet | `YYYY-MM-DD`, the first day (UTC). Without it, only markets that haven't ended: their `event_time` is now or later, or they have none. |
| `to` | none | `YYYY-MM-DD`, the last day (UTC). `from` and `to` filter on the same time the list sorts by. |
| `venues` | any | Listed on **all** of these: `venues=kalshi,polymarket_us`. Names: `kalshi`, `polymarket`, `polymarket_us`, `novig`, `hyperliquid`. |
| `event_id` | none | Every market of one game or occasion. |
| `limit`, `offset` | `50`, `0` | Page size (1–200) and how many to skip. |
| `prices` | `true` | `false` leaves out prices and best trades, for a faster answer. |

## GET /v0/markets/{id}

One market, with live prices and best trades.

```
curl -H "Authorization: Bearer $LAYER_API_KEY" "https://uselayer.sh/v0/markets/lyr_60a98333e4c6"
```

```json
{
  "market": {
    "id": "lyr_60a98333e4c6",
    "event_id": "lyr_evt_781c1f1f4743",
    "category": "sports",
    "question": "Union Santa Fe vs Velez Sarsfield: Velez Sarsfield wins",
    "event_time": "2026-11-07T01:00:00.000Z",
    "status": "open",
    "listings": [
      {
        "venue": "kalshi",
        "market_id": "KXARGPREMDIVGAME-26NOV06UNIVEL-VEL",
        "url": "https://kalshi.com/markets/kxargpremdivgame/x/kxargpremdivgame-26nov06univel",
        "basis": "identical",
        "caveats": [],
        "reference": true,
        "outcome": "Velez Sarsfield",
        "price": {
          "yes": { "bid": { "price": 0.36, "size": 1262.4 }, "ask": { "price": 0.37, "size": 3437.12 } },
          "no": { "bid": { "price": 0.63, "size": 3437.12 }, "ask": { "price": 0.64, "size": 1262.4 } }
        }
      },
      {
        "venue": "polymarket_us",
        "market_id": "atc-lpa-uni-vel-2026-11-06-vel",
        "url": "https://polymarket.us/event/lpa-uni-vel-2026-11-06",
        "basis": "identical",
        "caveats": [],
        "outcome": "CA Vélez Sarsfield (Reg. Time)",
        "price": {
          "yes": { "bid": { "price": 0.35, "size": 1777 }, "ask": { "price": 0.37, "size": 1400.5 } },
          "no": { "bid": { "price": 0.63, "size": 1400.5 }, "ask": { "price": 0.65, "size": 1777 } }
        }
      }
    ],
    "prices_as_of": "2026-11-06T03:26:37.655Z",
    "best_trade": {
      "kalshi": { "buy": "no", "price": 0.64, "size": 1262.4 },
      "polymarket_us": { "buy": "yes", "price": 0.37, "size": 1400.5 },
      "contracts": 1262,
      "cost": 1274.62,
      "fees": 40.8,
      "payout": 1262,
      "net_profit": -53.42,
      "net_profit_per_contract": -0.04233,
      "return_pct": -4.06,
      "profitable": false,
      "expected_payout_at": "2026-11-07T07:00:00.000Z",
      "days_held": 1.15,
      "listings": [
        { "venue": "kalshi", "market_id": "KXARGPREMDIVGAME-26NOV06UNIVEL-VEL", "basis": "identical", "caveats": [] },
        { "venue": "polymarket_us", "market_id": "atc-lpa-uni-vel-2026-11-06-vel", "basis": "identical", "caveats": [] }
      ]
    },
    "best_trade_any": { "…": "the same trade as best_trade here: both listings are identical" }
  },
  "attribution": "Market data from Kalshi (kalshi.com) and Polymarket US (polymarket.us). Each market's url links to its page on the venue, where it's traded."
}
```

How to read it:
- **The trade:** buy NO on Kalshi at 64¢ and YES on Polymarket US at 37¢, for 1,262 contracts.
- **What it costs:** $1,274.62, plus $40.80 in fees, to get $1,262 back. That's a loss of $53.42, so `profitable` is `false`. Most of the time there's no free money; when there is, `profitable` is `true`.
- **Shortened:** some fields are left out here to keep it short, such as each listing's `question`, `group_id` and `series`, and the trade's `latest_payout_at` and per-day returns. [All fields](#all-fields) lists them.

Layer ids never change. If two markets are merged, the old id answers with the one it became, and `merged_from` says so.

## GET /v0/markets/lookup

Find the Layer market from any venue's market id.

```
curl -H "Authorization: Bearer $LAYER_API_KEY" "https://uselayer.sh/v0/markets/lookup?venue=kalshi&market_id=KXARGPREMDIVGAME-26NOV06UNIVEL-VEL"
```

This answers with the same `market` as above. When there's no Layer market for it, `market` is `null` and `reason` says why:

```json
{
  "market": null,
  "reason": "no_twin_yet",
  "detail": "Layer knows this market, but no other venue it serves lists the same question yet."
}
```

| `reason` | Meaning |
|---|---|
| `no_twin_yet` | No other venue lists the same question yet, or a new match hasn't reached Layer markets yet (they're updated in batches, so they can lag `/v0/matches`). |
| `under_review` | Its listing is held while its match or settlement is checked. |
| `unknown_market` | Layer hasn't read that market id. |
| `venue_not_served` | That venue isn't served right now. |

For polymarket.com, the condition id, the numeric id or the slug all work: `<slug>` for a Yes/No market, `<slug>:<i>` for one outcome of a multi-outcome market.

## Moving from /v0/matches

Nothing changes unless you want it to. `/v0/matches` stays as it is.

- **One item instead of several.** One `/v0/markets` item is all the `/v0/matches` items that share a Kalshi market, across venues. Your Kalshi ↔ Polymarket US pair is the market's `kalshi` listing plus its `polymarket_us` listing.
- **Basis per listing.** `basis` and `caveats` are on each listing, compared with the reference, instead of on the pair.
- **Find yours.** Have a match from `/v0/matches`? Call `/v0/markets/lookup?venue=kalshi&market_id=<kalshi.market_id>`.
- **Lag.** Layer markets can lag `/v0/matches` for new matches.

## Errors

| Status | `error` | When |
|---|---|---|
| 400 | `bad_request` | A filter Layer can't read; `detail` says which. |
| 401 | `unauthorized` | No key, or the key is unknown or revoked. |
| 403 | `markets_not_enabled` | Your account doesn't have early access yet. |
| 404 | `not_found` | `/v0/markets/{id}`: no Layer market with that id. |
| 429 | `rate_limited` | Over 60 requests/minute, as for every `/v0` endpoint. Wait `retry-after` seconds. |
| 503 | `markets_unavailable` | Briefly, right after a deploy. Try again in a few minutes. |

## Not yet

- **Live 15-minute crypto windows.** They're in `/v0/matches`. `/v0/markets` has crypto price levels, but not yet the short windows.
- **Markets Kalshi doesn't list.** Every Layer market today includes a Kalshi listing.
- **Settled markets** (`/v0/markets/settled`), Gemini, and crypto price ranges.
- **Hyperliquid best trades.** Hyperliquid listings get a price but no best trade: its fees aren't modelled.

## All fields

| Field | Meaning |
|---|---|
| `id`, `event_id` | The market's Layer id, and its game's or occasion's. |
| `status` | `open`, `closed` (trading over) or `settled`. The list returns only open markets; `/{id}` and lookup return any. |
| `question`, `start_time`, `event_time` | Shown when every venue on the market allows Layer to show its data; otherwise left out. On a market that includes polymarket.com, they're missing. `start_time`: when the game or window starts (ISO 8601), or `null` when Layer doesn't know it yet. `event_time`: for a game, the venue's expected settle time, a few hours after the start; for a crypto window, its end. |
| `reference_hidden` | `true` when the reference listing isn't shown (its venue isn't served, or it's under review). The other listings' `basis` still holds. |
| `listings[].reference` | `true` on the listing the others are compared with: Kalshi's when it's there. |
| `listings[].question`, `outcome` | The venue's own wording, where that venue allows it. |
| `listings[].group_id`, `series`, `slug` | The venue's event, series and (for polymarket.com) slug. |
| `listings[].price` | `null` only when that venue's prices couldn't be read; a side with no order has a `null` bid or ask (an ended game shows them all `null`). |
| `prices_unavailable` | At the top of the answer: venues whose prices couldn't be read this time. |
| `best_trade`, `best_trade_any` | `null` when no pair has both asks. Priced like [`POST /v0/profit`](https://uselayer.sh/docs/api.md#post-v0-profit). |
| `attribution` | One sentence naming every venue on the answer once. Show it wherever you show the data. |
