Every authenticated endpoint expects a Bearer JWT in the `Authorization` header. Keys are issued from the merchant dashboard, scoped to your account, and signed by RefCampaign.

## Generate an API key

1. Open **Settings → API keys** in the merchant dashboard.
2. Click **Create API key** and give it a descriptive name (e.g. `production-server`, `ci-backfill`).
3. Copy the token. The dashboard shows it once — there is no recovery.
4. Store the token in a secret manager (Vercel, AWS Secrets Manager, GitHub Actions secrets…). Treat it like a password.

## Use a key

Send the token on every API request:

```http
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
```

curl example:

```bash
curl https://app.refcampaign.com/api/v1/campaigns \
  -H "Authorization: Bearer $REFCAMPAIGN_API_KEY"
```

The token is opaque to your application. Do not parse it — its format may change between releases.

## Token lifetime

API keys do not expire by default. They remain valid until you revoke them from the dashboard.

If you need rotating short-lived tokens (a common security control), rotate them yourself:

1. Generate a new key.
2. Roll the new value out to your servers.
3. Revoke the old key once the rollout is complete.

## Revocation

In **Settings → API keys**, click **Revoke** next to the key. Active sessions on that key fail immediately with `401`. Revocation is permanent — you cannot un-revoke.

A revoked key returns:

```json
{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired API key"
  }
}
```

## Public endpoints

A small number of endpoints accept anonymous traffic (rate-limited per IP):

* `POST /api/v1/track/click` — click tracking from the browser SDK.
* `POST /api/v1/track/identify` — session-to-customer binding.
* `POST /api/v1/affiliates/signup` — public affiliate self-registration.
* `GET /api/v1/campaigns/{id}/public` — public campaign profile for landing pages.

These endpoints do NOT require an `Authorization` header. They have stricter rate limits and reject malformed payloads with the same error envelope.

## Security checklist

<Callout type="danger" title="Never commit a key to git">
  Even in a private repo, leaked keys end up in CI logs, archived branches, and forks. Use environment variables and a secret manager — and rotate immediately if a key was ever committed.
</Callout>

* **Use a dedicated key per environment.** Don't share the production key with staging or local dev.
* **Rotate after a suspected leak.** Generate a new key, deploy it, revoke the old one.
* **Limit blast radius.** If a service only needs to read commissions, eventually you'll be able to scope the key to that surface — for now, treat every key as full-account access.
