# IP allowlists (IP whitelisting)
Source: https://docs.tensormachine.ai/console-management/ip-allowlists

## The mental model — it's per **team**

An IP allowlist restricts **which source IPs are allowed to call the API** with a key. It is a
property of a **team**, not of an individual key or the whole org:

- Every key issued under a team — your personal keys and the team's durable keys alike —
  inherits that team's allowlist.
- Different teams can have different allowlists (e.g. a `prod` team locked to your data
  centre's egress range, a `sandbox` team left open).
- Set it once on the team; you don't (and can't) set it key-by-key.

An **empty** allowlist means **allow all IPs** (the default). A **non-empty** allowlist is
**deny-by-default**: only requests from a listed range are served — everything else is refused.

<Callout type="info">
  Because it's team-scoped, moving a key to another team (or minting one there) makes it follow
  **that** team's allowlist. Keep production workloads on a team whose allowlist you control.
</Callout>

## How to set it

**Console → your team → Guardrails &amp; policy → IP allowlist** (organization owner/admin).

1. Enter one **CIDR block** or **bare IP** per line. Examples:

   ```
   203.0.113.0/24
   198.51.100.7
   2001:db8::/32
   ```

2. **Save.** Entries are validated on save — a malformed line (e.g. `203.0.113/24` or an IP
   range `a-b`) is rejected with an error naming the bad entry, so nothing half-valid is stored.
3. The change takes effect **immediately** — it's pushed to the edge for the team's existing
   keys; you do **not** need to rotate or re-mint keys.

To turn enforcement **off**, clear the box (empty = allow all) and Save.

### Accepted formats

| You can enter | Meaning |
|---|---|
| `203.0.113.0/24` | an IPv4 CIDR block (256 addresses) |
| `198.51.100.7` | a single IPv4 address |
| `2001:db8::/32` | an IPv6 CIDR block |
| `2001:db8::1` | a single IPv6 address |

Blank lines are ignored. Order doesn't matter — a request is allowed if it matches **any** entry.

## Which IP we match

We match the **source IP of the request as it reaches our edge**. If your application egresses
through a **NAT gateway, VPN, or forward proxy**, that shared **egress** address is what we see —
not the private/internal IP of the machine making the call.

<Callout type="warn">
  Allowlist your **egress / NAT / VPN CIDR**, not your internal subnet. If you're unsure of your
  egress IP, call any endpoint from the same network and check the source IP, or ask your network
  team for the outbound NAT range.
</Callout>

## What a blocked request looks like

A request from a non-allowlisted IP is refused **before** it reaches a model:

```
HTTP/1.1 403 Forbidden
Content-Type: application/json

{ "detail": "client IP not allowed" }
```

If a legitimate client is unexpectedly blocked, it's almost always because the **egress IP**
differs from what's listed (a new NAT range, a VPN change, or an office without the VPN) — verify
the actual source IP and add its range.

## Notes

- The allowlist is checked on **every** request, independently of your API key, rate limits, and
  budgets — a valid key from a disallowed IP is still refused.
- Tightening the list is safe to do mid-incident: it applies to live keys at once.
- Leaving the list empty is not a mistake — it's the explicit "allow all" default; only add
  entries when you want to restrict access.
