A retirement (a player quits mid-match through injury or illness) or a walkover (a player withdraws before play begins) can settle a tennis event market without a normal final score. What actually happens to the market depends on each venue's published resolution rules — Polymarket and Kalshi each define their own. The reliable engineering move is to read that rule from the market itself and detect the status change in your live-data feed so your bot reacts in time.
This article explains the concept, why it matters for anyone building on tennis event markets, and how to detect a retirement or walkover in live match-status data — the part we can help with directly. It is educational, observe-only, and not financial advice.
What retirements and walkovers mean for a tennis market
A tennis market usually assumes a match ends with one player winning the last point. Retirements and walkovers break that assumption:
- Retirement (RET): play has started, then one player stops. There is a "winner" by the rules of the event, but no completed final set.
- Walkover (W/O): the match never starts because a player withdraws (illness, injury, admin). One side advances without a ball struck.
For a market, the open questions are: Does a retirement count as a win for resolution? Is a walkover a valid result, a void, or a push? Those answers are not universal — they are set per venue, and sometimes per market.
The honest rule: read the resolution text, don't assume it
Here is the part builders get wrong. We do not set resolution rules and neither should your code assume them. Each venue publishes its own, and on Polymarket the rule text ships inside the market object itself.
When you pull a tennis market from Polymarket's public Gamma API (https://gamma-api.polymarket.com, tennis tag 864), each market carries a human-readable description and often a resolutionSource. That description is where the resolution logic — including how edge cases resolve — is stated by the venue. Read it programmatically instead of hard-coding an assumption:
# Discover live tennis markets on Polymarket (keyless, public)
import requests
r = requests.get("https://gamma-api.polymarket.com/markets",
params={"tag_id": 864, "closed": "false", "limit": 5}, timeout=10)
for m in r.json():
# The resolution logic lives in the market's own text — read it, don't assume.
print(m["question"])
print(" resolutionSource:", m.get("resolutionSource", "(stated in description)"))
The description field is prose written by the venue; parse it, surface it to yourself, and link back to the venue's official rules rather than treating any single interpretation as fact. For Kalshi — a separate, regulated US venue with its own public API and tennis event series — the equivalent contract lives in that market's rulebook/terms; consult Kalshi's official market rules for how retirements and walkovers settle there. When in doubt, treat the venue's published rule as the source of truth and your job as detecting the triggering event accurately.
The current wording, verbatim. We keep a dated, side-by-side copy of the actual rule text from polymarket.com, Polymarket US and Kalshi (ATP/WTA vs ITF) in Polymarket & Kalshi tennis retirement/walkover rules (2026) — walkover = 50-50 on polymarket.com, last fair market price on Polymarket US (ITF $0.50), fair price on Kalshi (ITF $0.50); an in-play retirement pays the advancing player on all three, except Kalshi ITF where the withdrawing player resolves No.
Where we help: detect the status change in live data
The genuinely useful, venue-neutral thing a data feed gives you is early, structured detection that a retirement or walkover has occurred. Every match object carries a closed-vocabulary outcome — completed, retired, walkover, default, abandoned (null until settled) — next to event_status, the feed's own designator (Retired, Walk Over, Cancelled, Postponed, Interrupted), and withdrew naming the player who stopped or conceded. The lifecycle status (upcoming / live / completed / cancelled) is a different field and does not carry these values. So your bot can see the event in the data feed instead of scraping a scoreboard.
Get a free key at livetennisapi.com/subscribe/free (no card). The free tier gives live matches and scores.
# Live matches with their current status (free tier)
curl -s "https://api.livetennisapi.com/api/public/v1/matches?status=live" \
-H "X-API-Key: YOUR_KEY"
A minimal poller that flags a non-normal ending:
import requests
BASE = "https://api.livetennisapi.com/api/public/v1"
HEADERS = {"X-API-Key": "YOUR_KEY"}
# `outcome` values that mean "this match did not end with a normal final score"
NON_NORMAL = {"retired", "walkover"}
def scan(tracked_ids):
# Re-read the matches you hold positions in. Do NOT scan ?status=live for
# this: a retired match leaves the live list the moment it ends, and a
# walkover declared before first serve was never in it. (ULTRA keys can
# subscribe signals:["status"] on the WebSocket instead of polling.)
for mid in tracked_ids:
r = requests.get(f"{BASE}/matches/{mid}", headers=HEADERS, timeout=10)
r.raise_for_status()
m = r.json()
if m.get("outcome") in NON_NORMAL:
p1 = m["players"]["p1"]["name"]; p2 = m["players"]["p2"]["name"]
print(f"[EVENT] {m['outcome'].upper()} ({m.get('event_status')}) -> "
f"match {mid}: {p1} vs {p2}, withdrew={m.get('withdrew')}")
# your logic: look up the matching market, re-read its resolution
# text, and decide what (if anything) to do per that venue's rules.
scan(TRACKED_IDS)
The pattern is: detect the outcome change in the data → find the matching market → re-read that market's own resolution text → act only on what the venue's rule actually says. The Polymarket tennis toolkit (MIT, observe-only) shows the discovery-and-matching side: pull tennis markets from Gamma, match them to live matches, and join them into one view you can watch.
Why detection speed matters
Between the moment a player retires and the moment a market formally resolves, the market is often still live and repricing. A bot that only learns about a retirement from the final settlement is reacting late. Reading outcome/event_status from the feed lets you recognize the situation as it happens — an in-play retirement is stamped within seconds of the feed stating it, while a walkover declared before first serve arrives through a short pre-start status poll (no live socket can push a match that never went live; the current cadence is in the API docs' "Status freshness" section) — while still deferring the market outcome to the venue's rules. Detection is a data problem (ours); resolution is a rules problem (theirs); execution — orders, wallets, keys — is yours.
Wrap-up
Retirements and walkovers are the tennis-market edge cases most likely to surprise a naive bot. Handle them by (1) never hard-coding a resolution outcome — read each venue's published rule, on Polymarket straight from the market's description/resolutionSource, on Kalshi from its official rulebook; and (2) detecting the retired/walkover status early from a live feed so your code reacts in time. Start from the Polymarket tennis bot pillar guide, and pair this with data-driven tennis trading signals where retirement risk is one input among several.
Educational only. Not financial advice. Resolution rules are set and published by each venue.