# Authentication

## Secret key (server side)

Send your secret key as a Bearer token:

```bash
curl https://api.intasend.com/api/v1/wallets/ \
  -H "Authorization: Bearer ISSecretKey_test_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
```

> **Keep secret keys secret**
Never put a secret key in a browser, mobile app or public repository. Anyone with it can move money from your account.

## Publishable key (client side)

A few endpoints are safe to call from the browser: [Checkout](https://developers.intasend.com/guides/collections/checkout/) and
[payment status](https://developers.intasend.com/guides/collections/overview/#check-payment-status). Pass your publishable key either
in the `X-IntaSend-Public-API-Key` header or as `public_key` in the body:

```bash
curl -X POST https://api.intasend.com/api/v1/payment/status/ \
  -H "X-IntaSend-Public-API-Key: ISPubKey_test_xxxx" \
  -H "Content-Type: application/json" \
  -d '{"invoice_id": "ABC123"}'
```

## Short-lived tokens

You can exchange your key pair for a JWT that is valid for **30 minutes**. This is useful when you
don't want the long-lived secret key sent on every request:

```bash
curl -X POST https://api.intasend.com/api/v1/auth/generate-token/ \
  -H "Content-Type: application/json" \
  -d '{"api_key": "ISPubKey_test_xxxx", "api_secret": "ISSecretKey_test_xxxx"}'
```

```json
{"token": "eyJhbGciOiJIUzI1NiIs…"}
```

Use it as `Authorization: Bearer <token>`. When it expires, requests fail with `401 Expired token`; request a new one.

## Roles

Each API key acts as the account owner. For team users, these roles apply:

| Action | Minimum role |
|---|---|
| Read wallets and transactions | Any |
| Initiate payouts, create chargebacks | Level-2 |
| Approve payouts, confirm OTPs | Level-3 |
| Everything | Administrator |

## IP whitelisting

You can restrict secret-key requests to specific IPs or CIDR ranges in the dashboard. Requests
from other IPs get `403 Access denied: IP not whitelisted.`

## Rate limits

| Scope | Limit |
|---|---|
| Payments, payouts and wallet endpoints | 1,500 requests/min |
| Other authenticated endpoints | 100 requests/min |
| Unauthenticated (checkout and similar) | 30 to 45 requests/min per IP |

Exceeding a limit returns `429` with a `Retry-After` header.
