layer docs

API reference

Base URL: https://uselayer.sh. All responses are JSON.

Authentication

Every endpoint except /v0/health needs a key from your dashboard:

authorization: Bearer lyr_your_key

x-api-key: lyr_your_key also works. Each key allows 60 requests per minute.


GET /v0/matches

Every live match, soonest event first. Use it to discover what Layer can answer. For example, this weekend's NFL matches: ?category=sports&q=nfl&from=2026-10-03&to=2026-10-05. A filter it can't read, such as from=Oct 5, returns 400 bad_request.

Query Default Meaning
limit 50 1–200
offset 0 Skip this many matches first, to page past limit.
category all Only matches in that category, e.g. sports. A category with no live matches yet returns count: 0.
from — Only events on or after this day (YYYY-MM-DD, the match's event_date).
to — Only events on or before this day.
q — Words that must all appear, ignoring case, somewhere in either venue's event title, question or outcome, or in Kalshi's series ticker or Polymarket's event slug (so league names such as nfl work). E.g. chiefs or fed december. Up to 200 characters.
venue polymarket Which Polymarket the matches are with: polymarket (polymarket.com) or polymarket_us (Polymarket US, polymarket.us).

Response

Field Meaning
count Number of matches returned.
matches[].kalshi The Kalshi market (see Market object).
matches[].polymarket The Polymarket market. With venue=polymarket_us this field is matches[].polymarket_us instead.
matches[].event_date The day the event happens (YYYY-MM-DD). When Kalshi only gives the date it settles by, this is Polymarket's earlier date for the event.
matches[].category Layer's category for the event.
matches[].confidence 0–1. 1 when a person approved the match.
matches[].basis identical or equivalent_with_caveats.
matches[].caveats Which rules differ (see Overview).
matches[].tier human_verified or auto_verified.
attribution Where the data comes from (see Using Layer data).
checked_at When this answer was produced.

GET /v0/match

The twin of one market on the other venue.

Query Required Meaning
venue yes kalshi, polymarket or polymarket_us — the venue of the id you pass.
market_id yes Kalshi: the market ticker. Polymarket: the conditionId, market slug, or numeric id. Polymarket US: the market slug; for a market with two named sides, <slug>:long or <slug>:short.
with no For a Kalshi market: which Polymarket to find its twin on, polymarket (the default) or polymarket_us.

Match found

Field Meaning
source_market The market you asked about.
matched_market Its twin on the other venue.
side Always same: YES on one pays like YES on the other.
tier, confidence, basis, caveats As in /v0/matches.
match_reason Who approved it and which outcomes were paired.
attribution Where the data comes from (see Using Layer data).
checked_at When this answer was produced.

No match — matched_market is null and reason says why. source_market is still the market you asked about, or null when Layer doesn't know the id or can't tell which side you mean (specify_outcome).

reason Meaning
not_indexed Layer doesn't know this id, or the market has closed.
no_candidate Layer found nothing on the other venue that could be the same bet.
pending_review A possible match exists but hasn't been approved yet.
rejected A possible match was checked and is not the same bet.
outcome_unmapped The events match, but this particular outcome has no twin.
rules_changed_pending_review A venue edited its rules since approval; re-checking.
specify_outcome This Polymarket market has two named sides; pass <conditionId>:0 or <conditionId>:1 (Polymarket US: <slug>:long or <slug>:short).

Market object

Field Meaning
venue kalshi, polymarket or polymarket_us.
market_id The id to use with the venue's own API.
group_id The venue's event id (Kalshi event ticker, Polymarket event slug).
event The event's full title.
question The market's own question.
outcome The outcome this contract pays on.
url The market's page on the venue, where it's traded. Link to it when you show the market.
close_time When the venue stops trading this market at the latest (ISO 8601, UTC), or null if the venue gives none. It can close earlier once the result is known, so it's often later than event_date.
resolution_sources Where the venue says it will look to settle the market: a list of { "name", "url" }, either of which can be null. Kalshi lists them per event; Polymarket gives a link and names it in its rules. Empty when the venue names none. When a match has the source_differs caveat, this is where the two sides differ.
slug, yes_token_id Polymarket only: the market slug and the CLOB token id for YES — what you trade with. Polymarket US markets have slug only (without the :long / :short side).

POST /v0/match

Look up many markets in one call: up to 50, from either venue, mixed freely. The whole call counts as one request against your key's 60 per minute.

curl -X POST -H "authorization: Bearer $LAYER_KEY" \
  -H "content-type: application/json" \
  -d '{"markets":[{"venue":"kalshi","market_id":"KXFEDDECISION-26OCT-C25"},{"venue":"polymarket","market_id":"afcq-ben-mau-2026-09-29-ben"}]}' \
  "https://uselayer.sh/v0/match"

Request body

Field Meaning
markets 1–50 lookups.
markets[].venue kalshi, polymarket or polymarket_us, as in GET /v0/match.
markets[].with Optional, as in GET /v0/match.
markets[].market_id Any id GET /v0/match accepts.

Response

Field Meaning
count Number of results, the same as the number of markets you sent.
results One per market, in the order you sent them. Each has the venue and market_id you sent, plus exactly the fields GET /v0/match returns: a match, or matched_market: null with a reason.
attribution, checked_at As in GET /v0/match, once for the whole answer.

A market Layer doesn't know comes back as not_indexed in its place in results; it doesn't fail the call. The call fails with 400 bad_request only if the body is malformed, and detail names the entry (for example markets.3.venue).


POST /v0/profit

Is buying one side on each venue profitable once fees are paid? You send the prices; Layer applies each venue's official fee schedule. Buying YES on one venue and NO on the other, for the same matched outcome, pays exactly $1 per contract however it settles. So the trade is profitable when the two prices plus both fees come to less than $1 per contract.

The trade is Kalshi plus one other venue: send kalshi and exactly one of polymarket or polymarket_us.

curl -X POST -H "authorization: Bearer $LAYER_KEY" \
  -H "content-type: application/json" \
  -d '{"contracts":100,"kalshi":{"price":0.42},"polymarket":{"price":0.55,"fee_rate":0.05}}' \
  "https://uselayer.sh/v0/profit"

Request body

Field Default Meaning
contracts required Contracts bought on each venue, a whole number up to 1,000,000.
kalshi.price required What you pay per contract on Kalshi, in dollars (0.42 is 42¢). Up to 6 decimal places.
kalshi.role taker taker if your order fills against the book, maker if it rests first.
kalshi.fee_type quadratic The series' fee_type from Kalshi's API: quadratic, quadratic_with_maker_fees or quadratic_with_combo_maker_fees. Only the last two charge makers.
kalshi.fee_multiplier 1 The series' fee_multiplier from Kalshi's API. Some series use 0.5, and fee-free ones use 0.
polymarket.price required What you pay per share on Polymarket, in dollars.
polymarket.role taker Polymarket charges takers only, so maker pays no fee.
polymarket.fee_rate — The market's feeSchedule.rate from Polymarket's API. Send this or category.
polymarket.category — Uses Polymarket's default rate for the category: crypto 0.07; sports, economics, culture, weather, other 0.05; finance, politics, mentions, tech 0.04; geopolitics (or world) 0.
polymarket.exponent 1 The market's feeSchedule.exponent.
polymarket_us.price required What you pay per contract on Polymarket US, in dollars. Buying NO at X is a YES order at 1 − X there; send X.
polymarket_us.role taker taker pays the fee; maker gets Polymarket US's rebate.
polymarket_us.fee_coefficient 0.0695 The market's feeCoefficient from Polymarket US's API: its taker rate.

price is the price of the side you buy on that venue. Pass the YES price on one venue and the NO price on the other.

Response

{
  "contracts": 100,
  "kalshi": { "price": 0.42, "role": "taker", "cost": 42, "fee": 1.71, "fee_rate": 0.07, "fee_multiplier": 1, "fee_type": "quadratic" },
  "polymarket": { "price": 0.55, "role": "taker", "cost": 55, "fee": 1.2375, "fee_rate": 0.05, "exponent": 1 },
  "payout": 100,
  "spread": 0.03,
  "gross_profit": 3,
  "fees": 2.9475,
  "net_profit": 0.0525,
  "return_pct": 0.05,
  "profitable": true
}
Field Meaning
kalshi.cost, polymarket.cost Price × contracts on each venue. The second leg is under the venue you sent: polymarket or polymarket_us, with its fee_coefficient in place of fee_rate and exponent.
kalshi.fee, polymarket.fee Each venue's fee for the order, in dollars.
payout $1 × contracts: what the pair pays whichever way it settles.
spread Per contract, before fees: $1 − Kalshi price − Polymarket price.
gross_profit Payout − both costs, before fees.
fees Both fees together.
net_profit Payout − both costs − both fees. Negative means you'd lose money.
return_pct Net profit as a percentage of everything you pay (costs plus fees).
profitable true when net_profit is above zero.

How fees are worked out

  • Kalshi: multiplier × rate × contracts × price × (1 − price), rounded up to the next cent. The rate is 0.07 for takers. Makers pay 0.0175, or 0.035 on combo series, but only on series whose fee_type includes maker fees. This follows Kalshi's fee schedule and matches its published fee table. Members whose balance is kept to $0.0001 may pay up to 1¢ less per order.
  • Polymarket: contracts × fee_rate × (price × (1 − price))^exponent, rounded to 5 decimal places, takers only (Polymarket's fees).
  • Polymarket US: fee_coefficient × contracts × price × (1 − price), rounded to the nearest cent with ties to even. Makers get a rebate of 0.0125 × contracts × price × (1 − price), shown as a negative fee. This follows Polymarket US's fee schedule and matches its published 100-lot table. Its volume rebates, paid weekly, aren't included.

You send the prices, so no venue data is served: /v0/profit keeps working when a venue's data is switched off (see Errors).

The answer assumes each order fills in full at the price you send, as a single order. It leaves out deposit and withdrawal costs, rebates, and any price movement while you trade. Fees change: if a venue's schedule differs from this, the venue's schedule wins.


GET /v0/health

No key needed. Is the API up and can it reach its database?

{
  "ok": true,
  "database": { "reachable": true, "ms": 62 },
  "venues": {
    "kalshi": { "open_events": 12587, "open_markets": 125458, "last_pull": "…" },
    "polymarket": { "open_events": 42935, "open_markets": 364647, "last_pull": "…" },
    "polymarket_us": { "open_events": 4032, "open_markets": 65561, "last_pull": "…" }
  },
  "live_market_pairs": 14,
  "live_market_pairs_by_venue": { "polymarket": 14, "polymarket_us": 9 },
  "checked_at": "…"
}

live_market_pairs counts live matches with polymarket.com; live_market_pairs_by_venue counts them for each Polymarket.


Errors

Status error When
400 bad_request Missing or invalid query parameters or body; detail says which field.
401 unauthorized No key, or the key is unknown or revoked.
403 venue_not_served Matches with that venue (venue) aren't available right now.
429 rate_limited Over 60 requests/minute. Wait retry-after seconds.
503 venue_unavailable Data from a venue is temporarily switched off (venues lists which), so matches are paused.
503 database_not_configured / database_unreachable Layer can't reach its database.

Using Layer data

Every /v0/matches and /v0/match answer includes an attribution line. The data comes from Kalshi and Polymarket, and trading happens on each venue. When you show a market to your users, credit the venue and link to its url. Use Layer data inside your own product; don't republish it as a standalone feed or aggregator. The full terms are at /terms.