# Regions & geo-routing

Turnix runs TURN servers in several regions. Each credential points at exactly one region, through the host `<region>.turnix.io`. Relaying through a region close to your users keeps latency low.

## How Turnix picks the region

For every [`POST /credentials/ice`](https://turnix.io/docs/api-reference/credentials) request, Turnix decides in this order:

1. **`fixed_region`**: use exactly this region. If the slug does not exist, the request fails with `422 {"error":"Specified Region Not Found"}`. If the region is offline or in maintenance, it fails with `422 {"error":"Region Offline"}`.
2. **`preferred_region`**: use this region if it exists and is online. Otherwise, silently fall through to step 3.
3. **GeoIP**: look up the location of the client IP (see below) and use the nearest region that is online.
4. **Fallback**: if the IP cannot be located, use the platform's default region.

Use `fixed_region` when you must keep traffic in one place, for example for data residency. Use `preferred_region` when you have a good default but would rather get a working credential than an error.

## Which IP is used for GeoIP

Turnix determines the client IP from the request, in this order:

1. the `X-TURN-CLIENT-IP` header
2. the first valid IP in the `X-Forwarded-For` header
3. the IP address of the connection

> **Warning: Forward the end user's IP**
>
> You call the API from your backend, so without a header Turnix sees your **server's** IP and picks the region closest to your data center, not to your user. Send the user's public IP in `X-TURN-CLIENT-IP`:
>
> ```bash
> curl -X POST https://turnix.io/api/v1/credentials/ice \
>   -H "Authorization: Bearer $TURNIX_API_TOKEN" \
>   -H "X-TURN-CLIENT-IP: 203.0.113.42"
> ```
>
> If your backend runs behind a load balancer, read the user's IP from your framework's trusted-proxy setting (for example `req.ip` in Express with `trust proxy`, or `request.remote_ip` in Rails), not from a raw header the user could forge.

## Listing regions

[`GET /regions`](https://turnix.io/docs/api-reference/regions) returns all public regions with their slug, location and status. The dashboard shows the same list, with each region's TURN hostname, under [Server](https://turnix.io/app/turn/server).

A region is usable when both `is_online` and `is_operational` are `true`.

## Regions and plans

On the **free plan**, credentials are issued only in regions marked `is_trial: true`. Requests for other regions behave as follows:

- `fixed_region` set to a non-trial region: `422 {"error":"Specified Region Not Found"}`
- `preferred_region` set to a non-trial region: ignored, GeoIP picks the nearest trial region

Paid plans can use every online region. See [Usage, limits & billing](https://turnix.io/docs/concepts/usage-limits).

## Region hostnames and ports

Every region serves the same set of transports on its host:

| URL | Transport | Use |
|-----|-----------|-----|
| `turn:<region>.turnix.io:3478?transport=udp` | UDP | Fastest; the default choice |
| `turn:<region>.turnix.io:3478?transport=tcp` | TCP | Networks that block UDP |
| `turns:<region>.turnix.io:443?transport=tcp` | TLS over TCP on port 443 | Strict firewalls and proxies that allow only HTTPS-like traffic |
| `turns:<region>.turnix.io:443?transport=udp` | DTLS on port 443 | Included for completeness; most browsers ignore it |

STUN is served globally at `stun:stun.turnix.io:3478`.

Always pass all URLs from the response to `RTCPeerConnection`. The browser tries them in parallel and uses the best one that works.
