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

# Authentication

> How organisation API keys and request signatures work.

# Authentication

Crypto checkout merchant APIs use **organisation API keys** with request signing. JWT bearer tokens used by the dashboard are **not** accepted on these endpoints.

## Headers

| Header                | Required | Description                                                                        |
| --------------------- | -------- | ---------------------------------------------------------------------------------- |
| `X-Wakapay-Key`       | Yes      | Public key of an active organisation API key                                       |
| `X-Wakapay-Timestamp` | Yes      | Unix timestamp in milliseconds                                                     |
| `X-Wakapay-Signature` | Yes      | Hex HMAC-SHA256 of `{timestamp}.{rawBody}`                                         |
| `Idempotency-Key`     | No       | Supported on [checkout session creation](/api-reference/create-a-checkout-session) |

## Signature

```
signature = hex(HMAC-SHA256(api_secret, timestamp + "." + raw_body))
```

Rules:

1. Use the **raw request body** exactly as sent on the wire
2. For requests with no body, sign using the same raw body the server sees (often an empty string when `rawBody` is unset)
3. Reject locally if `|now - timestamp| > 5 minutes` to avoid wasted retries
4. Rotate keys from the [dashboard](https://account.wakapay.cash) if a secret is exposed

Only [creating a checkout session](/api-reference/create-a-checkout-session) requires signed API-key headers. Status, select-crypto, and bind-tx endpoints are used by the checkout flow without merchant signing.

## Scopes

API keys carry scopes. A valid signature with the wrong scope still returns `401`.

## Security checklist

* Never embed the API secret in a mobile app or browser
* Prefer server-to-server calls from your backend
* Store secrets in a vault or encrypted secret manager
* Verify [webhook](/webhooks) signatures with the organisation webhook secret (separate from the API key secret)

Website: [wakapay.cash](https://wakapay.cash)
