> ## Documentation Index
> Fetch the complete documentation index at: https://ahasend.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> AhaSend stores all message data in the EU. See /facts.
> The API base URL is https://api.ahasend.com. Send the API key in the Authorization: Bearer header. See /api-reference/authentication.
> Use send.ahasend.com for SMTP. Ports 25, 587 and 2525 use STARTTLS. Port 465 is not supported. See /smtp.
> For send-only integrations, create an API Key v2 under Credentials → Add and scope it to messages:send:{your-domain}. See /send-api/credentials and /api-reference/scopes.

# IP Allow Lists for API Keys

> Lock AhaSend API keys to specific IPv4/IPv6 addresses or CIDR ranges (up to 100 entries) so a leaked key can't be used outside your infrastructure.

AhaSend API key IP allow lists limit where a key can be used; this guide shows how to add allowed addresses and avoid locking yourself out.

Available on Free, Pro and Max. See [plans and features](https://ahasend.com/docs/facts.md#plans-and-features).

> [!NOTE]
>
> **Scope of this feature:** IP allow lists apply to Full API keys only. SMTP credentials and sending credentials are not affected.

## How it works

Every API key carries an `ip_allow_list`. It is empty by default, and an empty list means no restriction, so existing keys keep working exactly as before.

When the list is not empty:

* Requests from an IP covered by an entry are processed normally.
* Requests from any other IP are rejected on every endpoint, regardless of the scopes granted to the key.
* Changes take effect immediately.

The IP check runs before scope validation, so it is not another permission dimension. It is a gate in front of the key.

> [!NOTE]
>
> **Prefer static addresses you own and control.** An allow list is only as stable as the IPs behind it. Egress from a fixed NAT gateway, a bastion host, or a dedicated server works well. Dynamic addresses do not.

## Blocked requests

A request made with a restricted key from an IP that is not covered by the list is rejected with **HTTP 403** on every v2 endpoint, whatever the key's scopes allow.

```json theme={null}
{
  "message": "Request rejected by the API key IP allow list"
}
```

> [!WARNING]
>
> **Do not parse the error message.** The API returns no stable machine-readable error code, and several conditions share HTTP 403. Treat any 403 as a request your key was not permitted to make, and check the key's allow list and scopes to find out which applied.

IP allow list checks run before the idempotency layer, so a blocked request is never stored or replayed against an `Idempotency-Key`. Retrying the same request from an allowed IP with the same key executes normally.

## Supported entries

You can enter individual addresses or CIDR ranges, in IPv4 or IPv6:

| Entry | Meaning |
| - | - |
| `203.0.113.4` | A single IPv4 address, stored as `203.0.113.4/32` |
| `2001:db8::1` | A single IPv6 address, stored as `2001:db8::1/128` |
| `198.51.100.0/24` | An IPv4 range covering 256 addresses |

A few rules apply when you save:

* Entries are canonicalized, which means host bits are masked, and duplicates are removed.
* A key can hold up to 100 entries after de-duplication. A longer list is rejected.
* The allow-all prefixes `0.0.0.0/0` and `::/0` are rejected. To remove a restriction, clear the list instead.

## Configure in the dashboard

**1. Open your API keys**

Go to **Settings** and then **API Keys**.

**2. Edit the key**

Click **Edit** on the key you want to restrict and scroll to the **IP Allow List** section at the bottom.

**3. Add addresses or ranges**

Click **Add IP address or range** and enter one address or CIDR range per field. Repeat for each entry you need.

**4. Save and confirm**

Save the change. Because this affects who can use the key, you are asked to confirm your identity before the change is applied.

To lift the restriction again, delete every entry and save. An empty list allows all IPs.

## Configure with the Management API

Set the `ip_allow_list` field when you [create a key](https://ahasend.com/docs/api-reference/api-keys/create-api-key.md), or when you [update an existing one](https://ahasend.com/docs/api-reference/api-keys/update-api-key.md). The same field is available on the sub-account API key endpoints.

```bash theme={null}
curl -X POST "https://api.ahasend.com/v2/accounts/{account_id}/api-keys" \
  -H "Authorization: Bearer aha-sk-your-64-character-key" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Production API Key",
    "scopes": ["messages:send:all", "domains:read"],
    "ip_allow_list": ["203.0.113.0/24", "198.51.100.7"]
  }'
```

To change the list on an existing key, send a `PUT` to the key's endpoint:

```bash theme={null}
curl -X PUT "https://api.ahasend.com/v2/accounts/{account_id}/api-keys/{key_id}" \
  -H "Authorization: Bearer aha-sk-your-64-character-key" \
  -H "Content-Type: application/json" \
  -d '{
    "ip_allow_list": ["203.0.113.0/24"]
  }'
```

An update replaces the list rather than merging into it, so send the complete set of entries you want the key to keep:

| Value sent | Result |
| - | - |
| Field omitted, or `null` | The existing list is left unchanged |
| `[]` | The list is cleared, and the key becomes usable from any IP |
| `["203.0.113.0/24"]` | The list is replaced with exactly these entries |

The field is always present on API key responses. An empty array means the key can be used from any IP.

> [!WARNING]
>
> **Self-lockout protection:** If a key updates its own allow list to a value that excludes the IP the request is coming from, the update is rejected with **HTTP 409** and nothing is persisted. Updating a sub-account key from a parent key has no such guard, so check the sub-account's egress IP before you restrict its keys.

## Related documentation

> [card] [Scoped API Keys](https://ahasend.com/docs/security/scoped-credentials.md)
>
> Restrict what a key can do with domain and permission scoping

> [card] [API Key Scopes](https://ahasend.com/docs/api-reference/scopes.md)
>
> Complete reference of available permission scopes

> [card] [Create API Key](https://ahasend.com/docs/api-reference/api-keys/create-api-key.md)
>
> Endpoint reference including the `ip_allow_list` field

## Related Guides

* [API authentication](https://ahasend.com/docs/api-reference/authentication.md), [Send-only API keys](https://ahasend.com/docs/send-api/credentials.md), [Permission scopes](https://ahasend.com/docs/api-reference/scopes.md).
* [Scoped credentials](https://ahasend.com/docs/security/scoped-credentials.md), [API key CLI](https://ahasend.com/docs/cli/commands/apikeys.md), [Create key API](https://ahasend.com/docs/api-reference/api-keys/create-api-key.md).
* [Plans and limits](https://ahasend.com/docs/facts.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.