Three venues, three different rule sets. A walkover on Polymarket settles 50-50; on Polymarket US it settles at the last fair market price (ITF: $0.50); on Kalshi it settles at a fair price per the rules (ITF: $0.50). A mid-match retirement pays the advancing player on all three — except Kalshi ITF, where the withdrawing player's contract resolves No. Below is every rule quoted verbatim from the venue, with the URL and the date we retrieved it, then the matching event_status / outcome values in live match data so your code reacts to the right branch.
Nothing here is advice. Rules are set per market and can change; the market's own description / rules_secondary text always wins over this page.
The settlement matrix (2026-08-23)
| Scenario | Polymarket (polymarket.com) | Polymarket US (docs.polymarket.us) | Kalshi (ATP/WTA) | Kalshi (ITF) |
|---|---|---|---|---|
| Walkover / withdrawal before the match starts | 50-50 | Last fair market price at announcement | Fair price per rules | $0.50 per contract |
| Match cancelled, not played | 50-50 | Last fair market price | Fair price per rules | $0.50 |
| Retirement after play starts (injury, default, DQ) | Advancing player wins | Awarded winner settles $1.00 | Winner resolves Yes ("after a ball has been played") | Winner Yes; withdrawing/forfeiting player No |
| Delayed / postponed | 50-50 if beyond 7 days with no winner | — (see venue FAQ) | Stays open, closes after rescheduled match (within two weeks) | Same as ATP/WTA |
| What counts as "started" | "the match begins" | First serve is struck | A ball has been played | A ball has been played |
"—" means the source we quote does not state it; read the specific market.
Polymarket (polymarket.com) — the rule lives in the market description
Every per-match tennis market on Polymarket carries its settlement text in the market object's description (public Gamma API, keyless). From a live ATP market, retrieved 2026-08-23 via https://gamma-api.polymarket.com/events?tag_id=864 (event atp-norrie-navone-2026-05-20):
If the match is canceled (not played at all), ends in a tie, or is delayed beyond 7 days from the scheduled date without a winner determined, this market will resolve to 50-50.
If the match begins but is not completed, and one player advances due to the opponent's retirement, default, or disqualification, this market will resolve to the player who advances.
If the match ends in a walkover (player withdraws before the start and the other advances automatically), this market will resolve to 50-50.
The primary resolution source will be official information from the ATP Tour. A consensus of credible reporting may also be used.
So on Polymarket a walkover is a 50-50, and a retirement is a win for the player who advances. The text is per market: read it from the API rather than assuming it.
# Read the settlement text straight from the market (keyless, public)
import requests
events = requests.get("https://gamma-api.polymarket.com/events",
params={"tag_id": 864, "closed": "false", "limit": 50},
timeout=10).json()
for ev in events:
if ev["slug"].startswith(("atp-", "wta-", "itf-")): # per-match events
m = ev["markets"][0]
print(ev["title"])
print(" walkover rule:", [s for s in m["description"].split("\n") if "walkover" in s.lower()])
Polymarket US (CFTC-regulated app) — first serve is the line
From the official Sports FAQ at docs.polymarket.us/faqs/sports-faqs, section Tennis (WTA, ATP, & ITF), retrieved 2026-08-23:
When does a match officially begin? A tennis match officially begins when the first serve is struck. Anything happening before the first serve (cancellation, walkover, withdrawal) is treated as a pre-event scenario and Contracts settle at last fair market prices as of the official announcement. Except in the case of ITF Men's and Women's matches, cancellation, walkover, or withdrawal will resolve at $0.50 per Contract.
Mid-match retirement, default, or disqualification. If a player retires after the first serve, defaults for a code violation, or is disqualified, the market resolves on the official result declared by the governing body. Whoever is awarded the win settles at $1.00, regardless of how many games or sets were completed.
Two things differ from polymarket.com: a pre-serve walkover is not a 50-50 but the last fair market price (so a 0.90 favourite's contract settles near 0.90, not 0.50) — unless it is an ITF match, which is $0.50.
Kalshi — per-market rules_secondary, and ITF is different
Kalshi publishes each market's wording in the public API (rules_primary / rules_secondary). Retrieved 2026-08-23 from https://api.elections.kalshi.com/trade-api/v2/markets?series_ticker=KXATPMATCH:
If Frances Tiafoe wins the Fils vs Tiafoe professional tennis match in the 2026 ATP Cincinnati Final after a ball has been played, then the market resolves to Yes. […] If the match does not occur (signaled by a ball being played) due to a player injury, walkover, forfeiture, or any other cancellation (all before the match starts), the market will resolve to a fair price in accordance with the rules. If this match is postponed or delayed, the market will remain open and close after the rescheduled match has finished (within two weeks).
The WTA series (KXWTAMATCH) carries the same text. The ITF series (KXITFMATCH, same date) adds two different clauses:
If the match does not occur (signaled by a ball being played) due to a player injury, walkover, forfeiture, or any other cancellation (all before the match starts), all markets will resolve to $0.50. If a player withdraws or forfeits after a match has started, that player will resolve to No.
Kalshi's series-level rulebook PDFs (e.g. assets.kalshi.com/regulatory/product-certifications/TENNISMATCH.pdf) are generic templates; the match-specific wording above is what the API returns per market.
# Kalshi: read the per-market rule text (public endpoint, no key needed for reads)
import requests
r = requests.get("https://api.elections.kalshi.com/trade-api/v2/markets",
params={"series_ticker": "KXITFMATCH", "status": "open", "limit": 5}, timeout=10)
for m in r.json()["markets"]:
print(m["ticker"], "->", m["rules_secondary"][:160])
Detecting each branch in live match data
The venue decides the payout; your feed has to tell you which branch happened, and when. In the Live Tennis API every match carries two settlement-relevant fields next to the lifecycle status:
outcome(closed vocabulary,nulluntil settled):completed,retired,walkover,default,abandonedevent_status(the feed's designator):Retired,Walk Over,Cancelled,Postponed,Interrupted, …withdrew: which player stopped or conceded
| Live data | Polymarket | Polymarket US | Kalshi ATP/WTA | Kalshi ITF |
|---|---|---|---|---|
outcome = walkover (never started) |
50-50 | Last fair price (ITF $0.50) | Fair price | $0.50 |
outcome = retired or default, withdrew = X |
Opponent of X wins | Opponent of X at $1.00 | Opponent of X = Yes | Opponent Yes, X = No |
event_status = Cancelled, never started |
50-50 | Last fair price (ITF $0.50) | Fair price | $0.50 |
event_status = Postponed / Interrupted |
Open until 7-day limit | See FAQ | Open up to two weeks | Open up to two weeks |
import requests
BASE = "https://api.livetennisapi.com/api/public/v1"
H = {"X-API-Key": "YOUR_KEY"} # free key: livetennisapi.com/subscribe/free
def settlement_branch(match_id: int) -> str:
m = requests.get(f"{BASE}/matches/{match_id}", headers=H, timeout=10).json()
if m.get("outcome") == "walkover":
return "pre-start walkover" # PM: 50-50 | PM US: LFMP (ITF 0.50) | Kalshi: fair price (ITF 0.50)
if m.get("outcome") in ("retired", "default"):
return f"in-play retirement, withdrew={m.get('withdrew')}" # advancing player paid on all venues
if m.get("event_status") in ("Cancelled",):
return "cancelled"
return m.get("event_status") or m.get("status") or "unknown"
The free tier returns status, event_status and outcome on live and upcoming matches; completed results (and the 60-second pre-start status poll that catches walkovers before first serve) are on Basic and up. The polymarket-tennis toolkit (MIT, observe-only) does the market-to-match join so you can print the venue's own rule text next to the live state.