> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.afternoon.co/llms.txt.
> For full documentation content, see https://docs.afternoon.co/llms-full.txt.

# Authentication

All Afternoon API endpoints (except the health check) require authentication via an API key sent as a Bearer token in the `Authorization` header.

## Obtaining an API key

API keys are created from the [Afternoon dashboard](https://afternoon.co/dashboard). Each key is scoped to a single company and has one of two modes:

| Mode     | Prefix     | Purpose                                             |
| -------- | ---------- | --------------------------------------------------- |
| **Live** | `ak_live_` | Production traffic and real billing data            |
| **Test** | `ak_test_` | Development and testing without affecting live data |

## Making authenticated requests

Include your API key in the `Authorization` header of every request:

```bash
curl https://api.afternoon.co/v1/customers \
  -H "Authorization: Bearer ak_live_YOUR_API_KEY"
```

## Error responses

The API returns specific error codes for authentication failures:

### Missing or malformed header

Returned when the `Authorization` header is absent or does not follow the `Bearer <token>` format.

```json
{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid Authorization header"
  },
  "request_id": "req_abc123"
}
```

**Status:** `401 Unauthorized`

### Invalid API key format

Returned when the token is present but does not match the expected `ak_live_*` or `ak_test_*` pattern.

```json
{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Invalid API key format"
  },
  "request_id": "req_abc123"
}
```

**Status:** `401 Unauthorized`

### Invalid API key

Returned when the token format is valid but the key does not exist.

```json
{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Invalid API key"
  },
  "request_id": "req_abc123"
}
```

**Status:** `401 Unauthorized`

### Revoked API key

Returned when the API key has been revoked from the dashboard.

```json
{
  "success": false,
  "error": {
    "code": "API_KEY_REVOKED",
    "message": "API key has been revoked"
  },
  "request_id": "req_abc123"
}
```

**Status:** `401 Unauthorized`

### Service unavailable

Returned when the authentication service cannot reach the database. Retry with exponential backoff.

```json
{
  "success": false,
  "error": {
    "code": "SERVICE_UNAVAILABLE",
    "message": "Authentication service unavailable"
  },
  "request_id": "req_abc123"
}
```

**Status:** `503 Service Unavailable`

## Rate limiting

Authenticated requests are subject to rate limits of 1,000 requests per 60-second window per company. Rate limit status is communicated via response headers:

| Header                  | Description                                   |
| ----------------------- | --------------------------------------------- |
| `X-RateLimit-Limit`     | Maximum requests allowed per window           |
| `X-RateLimit-Remaining` | Requests remaining in the current window      |
| `X-RateLimit-Reset`     | Unix timestamp when the current window resets |

When the limit is exceeded, the API returns a `429 Too Many Requests` response.

## Security best practices

<Note>
  Never expose API keys in client-side code, public repositories, or browser requests. Always send API calls from your server.
</Note>

* **Rotate keys regularly** — Generate new keys and revoke old ones from the dashboard.
* **Use test keys for development** — Keep `ak_test_` keys for staging and local development. Use `ak_live_` keys only in production.
* **Store keys securely** — Use environment variables or a secrets manager. Never commit keys to source control.
* **Monitor usage** — Check the dashboard for unexpected spikes in API usage that may indicate a compromised key.