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 caseRecommended
Merchant server creating / querying invoicesAPI key
Building a custom dashboardJWT
Responding to a webhookN/A — verify signature instead
CI job running end-to-end testsAPI 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.