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

# API Keys

> How to manage your Niftipay API keys, rotate keys with zero-downtime grace periods, and restrict access with IP allowlisting.

# API Keys

Niftipay uses API keys to authenticate server-to-server requests. You can create keys from the dashboard under **Settings > API Keys**.

This page covers:

* IP allowlisting (restrict which IPs can use your key)
* Key rotation (swap keys with a zero-downtime grace period)

> All endpoints below require authentication via `x-api-key` header or dashboard session.

***

# IP Allowlisting

Restrict which server IPs are allowed to use your API key. When no IPs are configured, **all IPs are allowed** (opt-in model).

Once you add at least one IP, only requests from allowlisted IPs will be accepted. Requests from other IPs will receive `403 Forbidden`.

Supported formats:

* **IPv4** — `203.0.113.50`
* **IPv6** — `2001:db8::1`
* **CIDR** — `203.0.113.0/24`

***

## List allowed IPs

`GET /api/user/api-keys/allowed-ips`

Returns your current IP allowlist.

**Example request**

```bash theme={null}
curl -X GET "https://www.niftipay.com/api/user/api-keys/allowed-ips" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

**Response (no IPs configured)**

```json theme={null}
{
  "allowedIps": [],
  "note": "No IP restrictions configured. All IPs can use your API key."
}
```

**Response (IPs configured)**

```json theme={null}
{
  "allowedIps": [
    {
      "id": "a1b2c3d4-...",
      "ip": "203.0.113.50",
      "label": "Production server",
      "createdAt": "2026-03-01T10:00:00.000Z"
    },
    {
      "id": "e5f6g7h8-...",
      "ip": "203.0.113.0/24",
      "label": "Office range",
      "createdAt": "2026-03-01T10:05:00.000Z"
    }
  ],
  "note": "2 IP(s) configured. Only these IPs can use your API key."
}
```

***

## Add an IP to the allowlist

`POST /api/user/api-keys/allowed-ips`

**Body**

```json theme={null}
{
  "ip": "203.0.113.50",
  "label": "Production server"
}
```

| Field   | Type   | Required | Description                       |
| ------- | ------ | -------- | --------------------------------- |
| `ip`    | string | Yes      | IPv4, IPv6, or CIDR notation      |
| `label` | string | No       | Friendly label for your reference |

**Example request**

```bash theme={null}
curl -X POST "https://www.niftipay.com/api/user/api-keys/allowed-ips" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{ "ip": "203.0.113.50", "label": "Production server" }'
```

**Response `201 Created`**

```json theme={null}
{
  "id": "a1b2c3d4-...",
  "ip": "203.0.113.50",
  "label": "Production server",
  "createdAt": "2026-03-01T10:00:00.000Z"
}
```

**Error responses**

* `400` — Invalid IP format
* `409` — IP already in allowlist

***

## Remove an IP from the allowlist

`DELETE /api/user/api-keys/allowed-ips`

Remove by `id` or by `ip` address (query parameter).

**Example request (by id)**

```bash theme={null}
curl -X DELETE "https://www.niftipay.com/api/user/api-keys/allowed-ips?id=a1b2c3d4-..." \
  -H "x-api-key: YOUR_API_KEY"
```

**Example request (by ip)**

```bash theme={null}
curl -X DELETE "https://www.niftipay.com/api/user/api-keys/allowed-ips?ip=203.0.113.50" \
  -H "x-api-key: YOUR_API_KEY"
```

**Response**

```json theme={null}
{ "ok": true }
```

**Error responses**

* `400` — Missing `id` or `ip` query parameter
* `404` — IP not found in allowlist

***

## IP allowlisting best practices

* **Always allowlist your production server IPs** before going live
* Use **CIDR ranges** if your servers share a subnet (e.g. `203.0.113.0/24`)
* **Add before removing** — when migrating servers, add the new IP first, verify it works, then remove the old one
* If you lock yourself out (removed all valid IPs), you can manage allowlisted IPs from the dashboard session

***

# API Key Rotation

Rotate your API key with **zero downtime** using a grace period. During the grace period, both the old and new keys are valid, giving you time to update your servers.

***

## Rotate a key

`POST /api/user/api-keys/rotate`

**Body**

```json theme={null}
{
  "oldKeyId": "old-key-id-here",
  "gracePeriodHours": 24,
  "name": "Production key v2"
}
```

| Field              | Type   | Required | Description                                                                             |
| ------------------ | ------ | -------- | --------------------------------------------------------------------------------------- |
| `oldKeyId`         | string | No       | ID of the key to retire. If omitted, a new key is created without expiring the old one. |
| `gracePeriodHours` | number | No       | Hours the old key stays valid (default: 24, max: 168 / 7 days)                          |
| `name`             | string | No       | Friendly name for the new key                                                           |

**Example request**

```bash theme={null}
curl -X POST "https://www.niftipay.com/api/user/api-keys/rotate" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{ "oldKeyId": "abc123", "gracePeriodHours": 48, "name": "Production key v2" }'
```

**Response**

```json theme={null}
{
  "newKey": {
    "id": "def456",
    "key": "nftp_live_new_key_shown_once...",
    "name": "Production key v2",
    "createdAt": "2026-04-13T10:00:00.000Z"
  },
  "oldKey": {
    "id": "abc123",
    "expiresAt": "2026-04-15T10:00:00.000Z",
    "gracePeriodHours": 48
  },
  "message": "New key created. Old key expires at 2026-04-15T10:00:00.000Z (48h grace period)."
}
```

**Response (without oldKeyId)**

```json theme={null}
{
  "newKey": {
    "id": "def456",
    "key": "nftp_live_new_key_shown_once...",
    "name": "Production key v2",
    "createdAt": "2026-04-13T10:00:00.000Z"
  },
  "oldKey": null,
  "message": "New key created. Pass oldKeyId to set a grace period on the previous key."
}
```

> The new key value is shown **once**. Store it securely immediately.

***

## Rotation best practices

### Recommended rotation steps

1. **Create the new key** with a grace period on the old key:

```bash theme={null}
curl -X POST "https://www.niftipay.com/api/user/api-keys/rotate" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "oldKeyId": "YOUR_OLD_KEY_ID", "gracePeriodHours": 48 }'
```

2. **Store the new key** in your environment variables / secret manager

3. **Deploy** your updated server(s) with the new key

4. **Verify** requests succeed with the new key

5. The old key **expires automatically** after the grace period — no manual cleanup needed

### Tips

* **Use at least 24 hours** of grace period to give yourself time to deploy across all environments
* **Rotate regularly** (e.g. every 90 days) as a security best practice
* If you need to **revoke immediately** (compromised key), set `gracePeriodHours: 0` — the old key expires instantly
* The new key has **no expiration** by default — it stays valid until you rotate again

***

# Troubleshooting

## Getting `403 Forbidden` after adding IPs

* Verify your server's **outbound IP** matches what you allowlisted (use `curl ifconfig.me` on your server)
* If behind a load balancer or proxy, allowlist the **external/NAT IP**, not the internal one
* CIDR notation must be valid (e.g. `203.0.113.0/24`, not `203.0.113.0/33`)

## Locked out of the API

* Log into the **Niftipay dashboard** (session auth bypasses IP allowlisting)
* Remove or update the IP allowlist from **Settings > API Keys**

## Old key stopped working before expected

* Check the `expiresAt` value returned during rotation
* Grace period is calculated from the moment of rotation, not from your last request
