The Polymarket geoblock endpoint is a public GET route at https://polymarket.com/api/geoblock that reports whether the requesting IP address is blocked from the international platform and which country it resolves to. It is a lightweight pre-check, not an authorization token: the CLOB order endpoints apply their own compliance layer, so a response of blocked:false does not guarantee that POST /order will succeed. This article explains the request and response shape, shows runnable checks in curl, Python, and JavaScript, and describes how to build a two-stage verification procedure that separates IP-level geoblocking from account, signing, and order-level failures.
What the geoblock endpoint actually answers
The route GET https://polymarket.com/api/geoblock is a public, unauthenticated check. It takes no API key, no signature, and no request body. Its job is to tell a caller whether the IP address that made the request is considered blocked for the international Polymarket platform, and to echo back the country code that the platform associated with that IP.
That scope is deliberately narrow. The endpoint describes the requesting IP, not your wallet, not your API credentials, and not the compliance state of the order book. It is the same class of check a frontend uses to decide whether to show a trading interface. Treating it as a trading authorization is the most common source of confusion: developers see blocked: false, then receive a 403 on order submission and conclude the endpoint is broken. It is not broken; it is answering a different question than the one they assumed.
This guide covers the request mechanics, the response fields, a reproducible two-stage test procedure, and the failure modes that sit between the geoblock check and a successful order. It does not publish a country allowlist, because those lists change and the endpoint itself is the authoritative live signal for the IP you are calling from.
- Public and unauthenticated: no API key, no HMAC signature, no wallet.
- IP-scoped: the answer depends on the egress IP of the machine making the call.
- Advisory for the frontend and pre-checks; the CLOB order path enforces separately.
- Country code in the response reflects IP geolocation, not account KYC data.
Assumptions and prerequisites
The procedures below assume you can make outbound HTTPS requests from the same host that will submit orders. That last clause matters: if you test from a laptop and trade from a cloud server, you are testing a different IP and possibly a different country. Run every check from the production egress path, or at minimum from a host with the same network egress.
You need a working HTTP client (curl, Python 3 with requests, or Node 18+ with built-in fetch), and for the order-stage test you need valid CLOB API credentials and a funded, approved wallet. If you only want the geoblock answer, no credentials are required at all. For the blockchain side of a trading stack, the RPC endpoint you use for Polygon reads and transaction submission is a separate dependency; see the multi-chain RPC endpoints guide and the RPC endpoints guide for how to choose and test one.
Mental model: two gates, not one
Think of Polymarket access as two gates in series. Gate one is the public geoblock check, which is cheap, cacheable, and IP-based. Gate two is the compliance layer in front of the CLOB trading endpoints, which evaluates the order request itself. Gate two can be stricter than gate one: it may use a tighter jurisdiction set, additional IP intelligence such as hosting-versus-residential classification or proxy flags, and context tied to the API key or wallet.
A useful analogy is a building with a lobby turnstile and a locked trading floor. The geoblock endpoint tells you whether the turnstile opens for your IP. It says nothing about whether the floor door will open for your credentials and your order. Both gates must pass, and they fail with different symptoms: gate one returns a JSON body with a boolean, gate two typically returns an HTTP 403 with an error message about trading being restricted in your region.
This is why the correct architecture is a pre-check plus a real submission test, not a pre-check alone. The pre-check is fast and free and belongs in your startup diagnostics and in any user-facing availability banner. The submission test is the only thing that proves the full path works.
Calling the endpoint with curl
The simplest invocation is a plain GET with no headers beyond what your HTTP client sends by default. Inspect both the status code and the body, because a proxy or captive portal can return a 200 with HTML that is not the geoblock JSON.
The -i flag prints response headers so you can confirm the content type, and --max-time prevents a hung connection from stalling a startup script. If your infrastructure routes through an HTTP proxy, add --proxy explicitly so the request leaves from the IP you intend to test.
curl -sS -i --max-time 10 \
-H 'Accept: application/json' \
https://polymarket.com/api/geoblock
# Expected shape (values depend on your egress IP):
# HTTP/2 200
# content-type: application/json
#
# {"blocked": false, "country": "XX"}Programmatic checks in Python and JavaScript
Wrap the call in a small function that returns a structured result rather than a raw string. The function should distinguish three outcomes: a valid JSON answer, a non-200 response, and a body that does not parse. Collapsing those into a single boolean hides exactly the failures you need to debug later.
The Python version below uses requests with a timeout and validates the presence of the blocked key. The JavaScript version uses the built-in fetch available in Node 18 and later, so it has no dependencies. Both log the country code so you can confirm the egress IP is where you think it is.
import requests
GEOBLOCK_URL = "https://polymarket.com/api/geoblock"
def check_geoblock(timeout=10):
try:
resp = requests.get(GEOBLOCK_URL, headers={"Accept": "application/json"}, timeout=timeout)
except requests.RequestException as exc:
return {"ok": False, "reason": f"transport error: {exc}"}
if resp.status_code != 200:
return {"ok": False, "reason": f"http {resp.status_code}", "body": resp.text[:200]}
try:
data = resp.json()
except ValueError:
return {"ok": False, "reason": "non-json body", "body": resp.text[:200]}
if "blocked" not in data:
return {"ok": False, "reason": "missing blocked field", "data": data}
return {"ok": True, "blocked": bool(data["blocked"]), "country": data.get("country")}
if __name__ == "__main__":
print(check_geoblock())
# --- JavaScript (Node 18+) ---
# const res = await fetch("https://polymarket.com/api/geoblock", {
# headers: { Accept: "application/json" },
# signal: AbortSignal.timeout(10000),
# });
# const data = await res.json();
# console.log({ status: res.status, blocked: data.blocked, country: data.country });A two-stage verification procedure with a results table
Run the following procedure from the production egress host and record each row in a table. Do not fill in expected values from memory; the point is to capture what your infrastructure actually returns and compare it against what your application assumes.
Stage one is the geoblock GET. Stage two is an authenticated, minimal order submission through the CLOB client, using a deliberately tiny size so that a successful placement is easy to cancel. If stage two is not appropriate for your environment, substitute an authenticated read that exercises the same credentials, such as a balance or open-orders query, and note in the table that the order path remains unverified.
The table columns below are the minimum needed to diagnose a mismatch. The egress IP column is essential: if two rows show different IPs, you are comparing different environments and the results are not comparable.
- | Check | Command or call | Observed status | Observed body | Egress IP | Country | Interpretation |
- | Geoblock GET | curl to /api/geoblock | (record) | (record) | (record) | (record) | blocked:false means gate one passed for this IP |
- | Authenticated read | CLOB balance or open orders | (record) | (record) | (record) | (record) | Proves credentials and signing are valid |
- | Minimal order | CLOB POST /order, tiny size | (record) | (record) | (record) | (record) | Proves gate two passed for this IP and account |
- | Repeat from second host | same three calls | (record) | (record) | (record) | (record) | Differences isolate IP-level effects |
Reading the response and confirming the egress IP
A healthy response is HTTP 200 with a JSON object containing a boolean blocked field and a country field holding a two-letter code. The country value is the platform's geolocation of your IP, so it is also a useful sanity check on your network path. If you believe you are egressing from one region and the endpoint reports another, investigate your NAT, proxy, or cloud provider's routing before investigating Polymarket.
Verification is straightforward: the blocked value should be consistent across repeated calls from the same host within a short window, and the country value should match the region your cloud provider assigns to that IP range. If either is unstable, you likely have a rotating egress pool or a proxy that load-balances across regions. That instability will also affect order placement, so fix it at the network layer rather than retrying in application code.
For the blockchain reads that accompany a trading bot, confirm your RPC path independently. A dedicated Polygon endpoint from a provider such as OnFinality's dedicated node service removes one variable from the stack, and you can compare plans on the RPC pricing page.
Why a passing geoblock check can still end in a 403
The most reported pattern is a blocked: false response followed by a 403 on order submission with a message that trading is restricted in the caller's region. The causes cluster into four groups, and each has a different fix.
First, different jurisdiction sets. The trading compliance layer may restrict a country that the public check does not flag, or may apply close-only semantics that permit reads but not new orders. Second, IP intelligence. Hosting-provider ranges, VPN exits, and proxy flags can be treated differently from residential IPs even when the country matches. Third, account and key context. An API key created under one region, or a wallet with a history associated with a restricted region, can carry flags that the IP check never sees. Fourth, the order itself. Signature type, funder address, and allowance problems produce errors that look similar in logs but are not geoblock failures.
The diagnostic discipline is to change one variable at a time. Confirm the egress IP, then confirm the credentials with an authenticated read, then submit a minimal order. If the read succeeds and the order fails with a region message, the problem is gate two, not your signing code.
- Region message on POST /order with successful GETs: suspect the trading compliance layer, not auth.
- Intermittent failures: suspect rotating egress IPs or a proxy pool spanning regions.
- Consistent 401 or signature errors: fix credentials before re-testing geoblock.
- Sudden change with no code deploy: re-run the table; jurisdiction lists and IP classifications change.
Enforcing the check inside your own application
If you are building an integration that surfaces Polymarket trading, mirror the platform's pattern: call the geoblock endpoint server-side, from the same egress as your order submission, and gate the trading UI on the result. Do not call it from the browser, because the browser's IP is the user's, not your server's, and the two can differ in ways that produce confusing behavior.
Cache the result briefly, on the order of minutes, keyed by egress IP. The check is cheap but not free, and a per-request call adds latency to every page load. More importantly, treat the cached value as advisory: always let the order submission be the final authority, and surface the platform's error message to the user rather than a generic failure.
The reference integration pattern published by Polymarket's own tooling follows this shape, and the safe-wallet integration reference is a useful read for the surrounding wallet and approval flow. For the RPC layer beneath it, the OnFinality API service and the supported networks list describe what is available without committing to a specific endpoint here.
// Server-side gate. Run on the same egress as order submission.
const GEOBLOCK_URL = "https://polymarket.com/api/geoblock";
const cache = new Map(); // key: egress label, value: { at, result }
async function geoblockFor(egressLabel, ttlMs = 120_000) {
const hit = cache.get(egressLabel);
if (hit && Date.now() - hit.at < ttlMs) return hit.result;
const res = await fetch(GEOBLOCK_URL, {
headers: { Accept: "application/json" },
signal: AbortSignal.timeout(10_000),
});
if (!res.ok) throw new Error(`geoblock http ${res.status}`);
const data = await res.json();
const result = { blocked: Boolean(data.blocked), country: data.country ?? null };
cache.set(egressLabel, { at: Date.now(), result });
return result;
}
// Usage: gate the UI, but never treat this as order authorization.
const gate = await geoblockFor("prod-egress-a");
console.log(gate.blocked ? "show read-only view" : "allow trading UI");Limitations and tradeoffs
The geoblock endpoint is a convenience signal, not a contract. Its response shape could change, its country mapping is derived from IP geolocation and therefore inherits the errors of that data, and it cannot see account-level or order-level restrictions. Building a compliance decision solely on this endpoint will produce both false positives (blocking users the trading layer would accept) and false negatives (allowing users the trading layer will reject).
There is also a latency and reliability tradeoff in calling it on every request. A short cache reduces load but widens the window in which a stale answer is shown. For a trading interface, the safer pattern is a cached advisory banner plus an authoritative error path on submission. Finally, the endpoint says nothing about the US-regulated platform, which is a separate product with its own documentation and authentication model; do not assume the international geoblock answer applies there.
If your application depends on low-latency Polygon access for the surrounding wallet and settlement flow, endpoint choice matters more than the geoblock call itself. The Hyperliquid low-latency provider comparison illustrates the measurement approach for latency-sensitive trading infrastructure, and the same method applies to any chain you use.
Next steps for a production integration
Turn the two-stage procedure into a startup self-test that runs on every deploy and writes its result to your logs with the egress IP attached. That single habit converts most region-related incidents from multi-hour debugging sessions into a one-line log lookup. Pair it with an alert if the geoblock answer changes for a stable egress, since that usually indicates either a network change on your side or a jurisdiction change on the platform's side.
For the concrete choice of RPC endpoint behind your trading stack, use the RPC Assistant rather than hardcoding a provider from an article; the best Ethereum RPC API comparison and the Web3 project provider guide describe the evaluation criteria, and the RPC endpoints guide covers the request patterns you will reuse. Keep the geoblock check, the authenticated read, and the minimal order test as three separate, independently logged signals, and you will always know which gate failed.