IP allow-list
An app with a write scope (orders.write, markets.write) registers the IP addresses it writes from, as CIDR blocks. The rule is:
- Calls that write must come from a registered address. Placing or cancelling orders and creating markets from any other address are refused with
403 ip_not_allowed, whatever the token. - Everything else works from any address. Markets, events, balances, positions, order and trade history and the live feeds are served wherever the call comes from, even when the token carries a write scope. So are token requests: code exchange, refresh and
client_credentials.
A token is not tied to the address that requested it. The check is made on each call, so a token requested anywhere writes from a registered address and only reads from any other.
A refused write
Section titled “A refused write”| Transport | A write from an unregistered address |
|---|---|
| REST | 403 with {"error": "ip_not_allowed", "error_description": "this app does not allow writes from this IP address"} |
| WebSocket | The connection is accepted and read topics join. A join that needs a write scope (joining orders:{user_id} with cancel_on_disconnect, and the combo negotiation topics) is refused with the join error ip_not_allowed |
So one app can serve both sides: read from your app servers, edge workers or a developer laptop, and keep trading and market creation on the servers you registered. Trading from your own machine? Add your public IP while you develop.
Handle 403 ip_not_allowed separately from 403 insufficient_scope: send writes from a registered address.

