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

# Authentication

> API key types and authentication methods

# Authentication

The ChainPal API uses API keys for authentication. All API requests must include a valid API key in the `Authorization` header.

## API Key Types

ChainPal provides two types of API keys for different use cases:

### Public Keys

* **Prefix**: `cp_pk_test_` or `cp_pk_live_`
* **Use Case**: Client-side integrations (e.g., initializing payments from your frontend)
* **Permissions**: Limited to creating payments and getting quotes
* **Endpoints**: `POST /payments`, `POST /payments/quote`

### Secret Keys

* **Prefix**: `cp_sk_test_` or `cp_sk_live_`
* **Use Case**: Server-side integrations only
* **Permissions**: Full API access including payment verification and listing
* **Endpoints**: All endpoints, including `GET /payments`, `GET /payments/:paymentId`, `GET /payments/:paymentId/verify`

<Warning>
  **Never expose your Secret Keys in client-side code**. Secret keys should only
  be used in server-to-server communications.
</Warning>

## Key Prefixes

The prefix encodes both the **type** (public vs secret) and the
**environment** (test vs live):

| Environment | Key Type | Prefix        |
| :---------- | :------- | :------------ |
| Test        | Public   | `cp_pk_test_` |
| Test        | Secret   | `cp_sk_test_` |
| Live        | Public   | `cp_pk_live_` |
| Live        | Secret   | `cp_sk_live_` |

## Test and Live keys are independent — use them side-by-side

There is no per-account "active environment" toggle. Each request is
routed by the prefix on the key you send:

* `cp_*_test_*` → request is processed in **test** mode
* `cp_*_live_*` → request is processed in **live** mode

This means you can run a staging integration against your test keys at
the same time your production servers are calling with live keys —
without flipping any switch.

What this implies for your integration:

* The `environment` field on every payment object reflects the env of
  the key used to create it. A payment created with a test key is and
  stays a test payment; same for live.
* Webhook URLs and callback URLs are configured **per environment**
  (`testWebhookURL` + `testCallbackURL`, `liveWebhookURL` +
  `liveCallbackURL`). The dispatcher picks the right pair based on the
  payment's env.
* Rate limits are tracked per `(business, environment)` bucket — test
  traffic doesn't eat into your live budget.

<Note>
  **Migrating from the old "switch environment" model?** The
  `POST /users/public-api/toggle-environment` endpoint is deprecated and
  returns `410 Gone`. Just send requests with whichever key matches the
  env you want.
</Note>

## Authorization Header

Include your API key in the `Authorization` header using the Bearer scheme:

```http theme={null}
Authorization: Bearer cp_pk_test_your_api_key
```

## Example Requests

### Using a Public Key (Initialize Payment)

```bash theme={null}
curl -X POST https://api.chainpal.org/api/v1/payments \
  -H "Authorization: Bearer cp_pk_test_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 5000,
    "customerEmail": "customer@example.com"
  }'
```

### Using a Secret Key (Verify Payment)

```bash theme={null}
curl https://api.chainpal.org/api/v1/payments/507f1f77bcf86cd799439011/verify \
  -H "Authorization: Bearer cp_sk_test_xyz789"
```

## IP Whitelisting

For enhanced security, you can configure IP whitelisting in your dashboard. When enabled:

* Only requests from whitelisted IP addresses will be accepted for Secret Key endpoints
* Requests from non-whitelisted IPs will receive a `403 Forbidden` response
* You can whitelist up to 3 IP addresses

IP whitelisting applies to the following endpoints:

* `GET /payments/:paymentId/verify`
* `GET /payments/reference/:reference/verify`
* `GET /payments/:paymentId`
* `GET /payments`

## Rate Limiting

API requests are rate-limited to prevent abuse:

| Key Type   | Default Rate Limit      |
| :--------- | :---------------------- |
| Public Key | 30 requests per minute  |
| Secret Key | 100 requests per minute |

When you exceed the rate limit, you'll receive a `429 Too Many Requests` response.

## Authentication Errors

| Status Code | Message                | Description                       |
| :---------- | :--------------------- | :-------------------------------- |
| `401`       | `api key is invalid`   | The provided API key is not valid |
| `401`       | `api key not provided` | No Authorization header was sent  |
| `403`       | `access denied`        | IP address not in whitelist       |
