oddsrail

Notes on the venue APIs

A geoblocked machine reads fine and fails only at the order

Polymarket and Kalshi enforce jurisdiction at order placement, not at connection. Every public read answers normally, so a restricted server looks perfectly healthy until the first trade.

Restrictions on both venues are enforced where the order is placed, not where the connection is made. Market data, order books, price history and resolution text all answer normally from a restricted machine. The first thing that fails is the trade.

For an agent that means the usual health check is worthless: everything it can test passes, and the failure arrives at the one call that is not idempotent.

The four failure shapes, which are not the same thing

  • Jurisdiction. An HTTP 403 or 451 at order placement. Retrying will never help, and an agent that treats it as transient will loop.
  • Network filter. Some ISPs return an HTML interstitial with a 200 status to a JSON endpoint. A parser that assumes JSON sees a decode error and reports "the venue is down".
  • Local TLS. A Python install with no CA bundle raises CERTIFICATE_VERIFY_FAILED on the websocket. That is a machine problem, not a venue problem, and the fix is SSL_CERT_FILE=$(python -m certifi).
  • Timeout wrapped by the SDK. A read timeout can surface as a generic transport error. "Nothing was sent" is not a safe thing to tell an agent after a timeout on a trade.

The advisory endpoint is advisory

Polymarket publishes polymarket.com/api/geoblock, and it is genuinely useful for a preflight. It is also IP-based and accepts unvalidated overrides, so ?country=ZZ answers blocked: false. "Not blocked" means "absent from a list", not "permitted", and the terms bind on residence and citizenship rather than on where your packets leave from.

What oddsrail does

It runs the preflight and reports the verdict as advisory, never as a gate, and it classifies every failure into one of those shapes with a hint that tells the agent what to do next: stop and tell the operator, fix the local CA bundle, or check whether the order rests before retrying. server_info shows the verdict and venue reachability before the first order of a session.

Found by driving the venues live, then encoded so an agent never rediscovers it. Reproduce every one of these with no keys: pip install oddsrail && python examples/footguns.py (source).

Try an agent that knows all six All notes