BlogPrediction markets

Polymarket API Guide for Developers Pricing Sports Contracts

The Polymarket API is how a program reads Polymarket's markets and its order book, and, with the right credentials, trades on them. Polymarket is a prediction market: each contract pays a fixed amount if an outcome happens and nothing if it doesn't, and prices are set by buyers and sellers on a central limit order book. A developer usually wants two things from it: the list of markets, and the best bid and ask on each one.

Everything that can change (endpoint paths, field names, authentication, rate limits, fees, which countries can trade, the terms) lives in Polymarket's own developer documentation, and that is the only place you should take it from. This guide covers what doesn't change: how to read a contract price, how to compare it with a sportsbook, and what to check before you build on it. ZippyOddsAPI is independent and not affiliated with Polymarket.

Where the Polymarket docs live

Start at Polymarket's official site and follow its link to the developer documentation. People search for the polymarket docs under several names, and they all mean the same set of pages. When you're reading the polymarket api docs, look for these four things before you write a line of code:

  1. Which service answers which question. Market listings, order book reads and trading are often separate services with separate base addresses. Read which one you need.
  2. What needs a key. Reading public market data and placing orders usually have different requirements. Confirm which one applies to your use.
  3. Rate limits. Find the published limits and what a refusal looks like, then build your backoff around them.
  4. Eligibility and terms. Who may trade, from where, and what you may do with the data are set by Polymarket, not by any third party. Read them yourself.

Bookmark the polymarket api documentation page that covers changes and versions too. A client that worked last month can break quietly when a field is renamed.

How to get Polymarket API key access

If you searched for how to get polymarket api key credentials, the honest answer is: follow the authentication section of the polymarket documentation, step by step, from Polymarket's own site. We won't repeat the steps here, because they can change and a stale guide is worse than none.

Two general rules hold for any trading key:

  • Treat it like a password to your money. Keep it in a secret store or an environment variable, never in source control, and never paste it into a site or tool you found through a search result.
  • Reading public prices may not need trading credentials at all. Check before you create keys you don't need.

The same caution applies to a polymarket cli. If you want a command-line tool, check Polymarket's documentation and its official code repositories for what the company itself publishes. A third-party tool that asks for your wallet or key deserves a careful read of its source before you run it.

From contract price to American odds

A contract that pays $1 and costs $0.62 implies a 62% chance. That's the whole conversion to a probability: the price is the chance, as long as you read the right price.

Which price is right matters. The ask is what you'd pay to buy now. The bid is what you'd get to sell now. The midpoint between them is not a price anyone will give you, so for a "what would I get" comparison, use the ask on the side you'd buy.

To turn a probability p into American odds:

  • If p is 0.5 or more: -(p / (1 - p)) * 100
  • If p is under 0.5: ((1 - p) / p) * 100, written with a plus sign

So an ask of $0.62 is about -163, and an ask of $0.35 is about +186. In decimal odds those are 1.613 and 2.857. Check the first one backwards: -163 implies 163 / 263, which is 61.98%. Close enough to 62% after rounding.

Here is the same thing in generic Python. It doesn't call any API.

def contract_to_american(p: float) -> int:
    """Contract price in dollars per $1 payout, 0 < p < 1."""
    if not 0 < p < 1:
        raise ValueError("price must be between 0 and 1")
    if p >= 0.5:
        return round(-(p / (1 - p)) * 100)
    return round(((1 - p) / p) * 100)

def contract_to_decimal(p: float) -> float:
    return 1 / p

for ask in (0.62, 0.35):
    print(ask, contract_to_american(ask), round(contract_to_decimal(ask), 3))
# 0.62 -163 1.613
# 0.35 186 2.857

Two things this leaves out on purpose. First, fees: whatever Polymarket charges on a trade changes what you really pay, so read the current fee schedule in its docs and add it to the price before converting. Second, depth: the best ask may only cover a few contracts. If you need more, the next level of the book is the price you'll actually get.

Comparing a contract with a sportsbook line

A sportsbook price carries a margin on both sides. A contract's spread between bid and ask is a cost too, but it's a different shape. To compare them fairly, remove the sportsbook's margin first (the prediction market API guide works a full example), then compare the no-vig chance with the contract ask after fees.

Keep the clocks honest. A contract ask read at one moment and a sportsbook price read a minute later aren't the same market. Store when each price was observed, and refuse to compare prices that are further apart than you can justify.

If you also read Kalshi, its streaming interface is a different design with its own rules: our Kalshi WebSocket API guide covers what to check there.

What ZippyOddsAPI holds for Polymarket

ZippyOddsAPI has a separate endpoint, /v1/prediction-contracts, that returns native Polymarket US contract catalog rows and best-bid/offer observations, as its documentation describes them. It's a raw channel, kept apart from sportsbook odds on purpose:

  • Every row is marked raw_only: true, scoring_eligible: false and execution_eligible: false, with payout and ev both null. ZippyOddsAPI doesn't turn these rows into game prices, best lines or EV.
  • Native ids and slugs are kept as Polymarket sends them. They are not ZippyOddsAPI game ids, and the docs say not to infer a home or away side from them.
  • native_quote_updated_at is currently null, because no native quote-update time is provided. The receipt and storage times are recorded, and neither is a quote-update time.
  • A last trade or a sample is kept apart from the best bid and ask, because a last trade isn't a current offer.

The request costs 2 credits, needs the futures scope and a plan with the futures feature, and returns JSON pages or a full NDJSON export. The API docs list every parameter and field, and explain how to ask the operator for a key.

Use it when you want stored observations next to your sportsbook data under one key. Use Polymarket's own API when you need its full catalog, live order book or trading, and follow its terms when you do.