# Create an allow or deny list

`POST /api/v1/ip/lists`

- Authentication: Secret API key as a bearer token
- Billing: Free.
- Group: IP

Saves a list of addresses and prefixes the account's lookups should treat as known-good (`allow`) or known-bad (`deny`): office and partner egress, a scraper's ranges, a fraud ring's space. Entries are IPv4 or IPv6 addresses or CIDR prefixes, canonicalised (an IPv4-mapped address collapses to dotted quad, `8.8.8.9/24` to `8.8.8.0/24`) and deduplicated before validation; a start-end range or a hostname is refused with `422`. The list applies from the account's next lookup.

An account may hold `meta.max_lists` lists (20) of `meta.max_entries` entries (5,000) each; the twenty-first answers `409 IP_LIST_LIMIT_REACHED`. Answers `201` with the list and its entries.

## Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | A label, answered back in `account_list.name` on every lookup the list matches. At most 100 characters. |
| `kind` | string | yes | `allow` zeroes the score of a matching address; `deny` adds the denylisted weight of 100. One of: allow, deny. |
| `entries` | string[] | yes | 1 to 5,000 IPv4 or IPv6 addresses or CIDR prefixes; duplicates and alternative spellings count once. |

## Example request

```bash
curl -X POST https://spaw.co/api/v1/ip/lists \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Office egress",
  "kind": "allow",
  "entries": [
    "203.0.113.0/24",
    "2001:db8:10::/48"
  ]
}'
```

## Responses

### 201 — The list was saved and applies from the next lookup.

```json
{
    "success": true,
    "data": {
        "list": {
            "id": 7,
            "name": "Office egress",
            "kind": "allow",
            "entry_count": 2,
            "created_at": "2026-09-12T09:00:00+00:00",
            "updated_at": "2026-09-12T09:00:00+00:00",
            "entries": [
                "203.0.113.0/24",
                "2001:db8:10::/48"
            ]
        }
    }
}
```

### 401 — The key is missing, malformed, or revoked.

```json
{
    "success": false,
    "error": {
        "code": "UNAUTHENTICATED",
        "message": "Provide a valid API key as a bearer token.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 409 — The account already holds as many lists as it may (`IP_LIST_LIMIT_REACHED`). Nothing was created.

```json
{
    "success": false,
    "error": {
        "code": "IP_LIST_LIMIT_REACHED",
        "message": "This account already holds 20 IP lists. Remove one, or add the entries to a list you have.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 422 — The request body could not be validated; `error.errors` lists the fields.

```json
{
    "success": false,
    "error": {
        "code": "VALIDATION_FAILED",
        "message": "The email field is required.",
        "errors": {
            "email": [
                "The email field is required."
            ]
        },
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 429 — Over 5 requests per second for the key. Retry after the limit resets.

```json
{
    "success": false,
    "error": {
        "code": "RATE_LIMITED",
        "message": "Too many requests. Retry after the limit resets.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

## Error codes

- `UNAUTHENTICATED` — https://spaw.co/docs/errors/UNAUTHENTICATED
- `VALIDATION_FAILED` — https://spaw.co/docs/errors/VALIDATION_FAILED
- `IP_LIST_LIMIT_REACHED` — https://spaw.co/docs/errors/IP_LIST_LIMIT_REACHED
- `RATE_LIMITED` — https://spaw.co/docs/errors/RATE_LIMITED

---

Canonical page: https://spaw.co/docs/api/create-ip-list · OpenAPI document: https://spaw.co/openapi.json · All endpoints: https://spaw.co/docs/api
