Authentication
JWT for dashboard sessions, per-merchant API keys for server-to-server calls, and how to use each.
The platform has two parallel authentication models.
1. JWT — for dashboard users#
When a user logs in via /api/auth/login, the backend issues an access token (short-lived, ~15 min) and a refresh token (longer-lived). Both are stored as HttpOnly cookies so browser JavaScript cannot read them.
This mode is used by the dashboard itself. You typically do not build against it — instead, your backend uses an API key (see below).
When you would use JWT#
- A custom merchant portal you want to build on top of our API.
- Scripts that operate as a specific user across merchants they own.
Endpoints#
POST /api/auth/register— create a user.POST /api/auth/login— exchange email + password for tokens.POST /api/auth/refresh— rotate the access token using the refresh token.POST /api/auth/change-password— authenticated password change.
2. API keys — for server-to-server#
Every merchant has a single API key. This key scopes every call to that one merchant.
- Issued on merchant creation. Rotated via the dashboard.
- Sent on every request in the
Authorization: Bearer <api-key>header. - Rotating invalidates the old key immediately — coordinate with any servers that use it.
When you would use API keys#
- Your backend creating invoices.
- Your backend reading invoice state.
- Any automated reconciliation job.
Webhook signatures — not authentication#
Webhook signatures (HMAC-SHA256 using the merchant's webhook_secret) are authentication of the platform to you, not authentication of you to the platform. They are covered separately in Verify webhook signatures.
Which model to use#
| Use case | Recommended |
|---|---|
| Merchant server creating / querying invoices | API key |
| Building a custom dashboard | JWT |
| Responding to a webhook | N/A — verify signature instead |
| CI job running end-to-end tests | API key on a dedicated test merchant |
Rotation#
- API keys: rotate from the merchant detail page. One click invalidates the old key and issues a new one. There is no grace period — deploy the new key first, then rotate, then restart callers.
- Webhook secrets: same model. See Retry failed webhooks if a delivery fails during the rotation window.
- JWT refresh tokens: rotated on every refresh. A long-idle user gets a fresh access token, then a fresh refresh token on next refresh.