Tokenized equities & geo-restrictions
SwapKit routes tokenized equities, ETFs and commodities. Their issuers restrict them in some jurisdictions, so send us your end user's IP and handle a 451.
SwapKit routes tokenized equities, ETFs and commodities — real-world assets, or RWAs. These are securities, and their issuers may not offer them to residents of certain jurisdictions, so they come with an enforcement layer that ordinary crypto assets don't have:
Tokens carry a
geoBlockRuleon token-list responses, naming the restriction that applies.A quote or swap involving a restricted token from a restricted jurisdiction is rejected with
451 Unavailable For Legal Reasons.Token discovery is never filtered by region —
/tokens,/tokens/search,/swapFromand/swapToreturn the same list to every caller.
There is one thing you need to do: tell us your end user's IP address. Send it as the left-most entry of X-Forwarded-For. If you call our API from your own backend and don't, we can only see your server's location — a London user behind a Virginia datacenter is assessed as Virginia.
A region we can't resolve is refused, not allowed, so an absent or unusable IP now costs you RWA quotes rather than only accuracy. Nothing else is affected — an ordinary swap is never region-checked.
Everything else is automatic. If you never quote an RWA, nothing about your integration changes.
The assets
Three issuers — Ondo, Robinhood and xStocks — across several chains and providers rather than one route, and roughly 600 contracts today: xStocks on Solana and Ethereum (SPYx, NVDAx, GLDx), Robinhood's equities on their own chain (AAPL, AMZN, COIN), Ondo's on BNB Smart Chain (TSLAon, SPYon, GLDon) — equities, index and bond ETFs, commodities and cash. Backed Finance's tokenized equity (SPCXx, on BSC) is restricted under the same rule. Identifiers follow the usual form:
BSC.TSLAon-0x2494b603319d4d9f9715c9f4496d9e0364b59d93Fetch the live set from /tokens rather than hardcoding a list — it grows as issuers are added.
Sending the end user's IP
Send the address as the left-most entry of X-Forwarded-For. Every proxy between you and us appends to the right, so the left-most entry is the one you set:
POST /v3/quote HTTP/1.1
x-api-key: <your key>
content-type: application/json
x-forwarded-for: 81.2.69.160Use X-Forwarded-For. X-User-Ip is accepted and takes precedence, but currently has no effect in production — a request carrying only that header is assessed on your server's location instead of your user's. We're investigating; until it's fixed, X-Forwarded-For is the only one that works end to end.
IPv4 only today. An IPv6 value is skipped rather than rejected, falling through to the next source — so an IPv6-only user with nothing else to go on ends up unassessed, and refused.
If you serve a browser client that talks to us directly, you can skip this: our edge determines the region for connections it terminates itself, and it's the last source we try.
Send it on /v3/swap too, not just the quote — see below.
The geoBlockRule field
GET /tokens and GET /tokens/search return an optional geoBlockRule naming which restriction applies. It's present only when one does, so treat its absence as "no rule known to apply".
tokenized-securities
Tokenized equities, ETFs and commodities whose issuers restrict them in sanctioned or non-serviced jurisdictions
It's a named rule rather than a boolean so that two issuers with different published restrictions can coexist, and so you can tell why an asset is fenced rather than only that it is.
Use it to badge these assets, gate them behind a disclosure, or group them into their own category. You do not need it for enforcement — that happens server-side either way.
These endpoints are never filtered by region, so a response is safe to cache and to share across your whole user base, and a short list is never a geo-block. Enforcement happens at quote and swap time, where you get an explicit 451 rather than a silently missing asset.
If you want restricted assets out of a particular user's picker, do it client-side from geoBlockRule — you know your user's jurisdiction better than we do from an IP.
To pull only these assets — or only ordinary crypto — pass category=rwa or category=crypto on /tokens and /tokens/search instead of filtering a full list yourself.
Handling a 451
A restricted asset quoted from a restricted region is rejected:
data.0 is the asset's display name, data.1 the resolved ISO 3166-1 alpha-2 country — or unknown when no source yielded one — and data.rule the rule that rejected it, the same value you saw on the token.
Build your own message from those fields rather than parsing the prose, and match on error === "geoRestrictedToken" rather than on the status code alone.
/v3/swap is checked independently
A routeId is portable, so the restriction is re-checked at execution against the assets the quote actually resolved to. A route priced from a permitted region cannot be executed from a restricted one — you get the same 451 at /v3/swap.
How enforcement works
Worth understanding, because it explains what you will and won't observe.
Restriction is per-token, and identity is the contract. A token is matched on its chain plus its lowercased contract address, never on its display symbol. Renaming a ticker doesn't change whether an asset is restricted.
Each rule owns its own jurisdiction list. The rule on the token is the key; the countries it blocks are resolved server-side.
An unknown region is blocked, not permitted. If no source yields a country, the quote is refused with the same 451 and the region reported as unknown. Only a request already naming a restricted token can reach that check — membership is looked up before any region is resolved.
Rejection costs nothing. The check is an index lookup, not a lookup plus a round trip, and it runs ahead of provider calls. A 451 adds no latency and consumes no provider quota.
Restricted jurisdictions
For tokenized-securities, the policy unions an issuer's published prohibited list (sanctions and unregistered-securities blocks) with its non-serviceable list — 27 countries at the time of writing, including the United States. It's drawn from Backed Finance's published restrictions, which Ondo's match in substance.
This list can change without notice, and without the rule name changing. Treat the API response as authoritative: don't replicate the list client-side, and don't assume a token permitted today stays permitted.
What this is and isn't
This enforces a jurisdictional restriction on specific instruments, using the location information you provide. It is not identity verification, sanctions screening or KYC — those are separate controls, and address screening continues to run as it always has.
Because the region derives from the IP you send us, the accuracy of that IP is your responsibility, and so is any obligation you have to establish where your users actually are. We enforce on what we are told.
Questions
Talk to your SwapKit contact if you need a different jurisdiction policy for your user base, want RWAs suppressed from your token lists entirely, or are unsure whether your requests are carrying the end user's IP — we can confirm what we're receiving from your key.
Last updated

