The API enforces three separate credentials. Which one an endpoint wants is shown in its reference page under Authorizations.

Bearer tokens

Both token types are JWTs and behave identically apart from which accounts they represent. When the Authorization header is absent, the API falls back to a cookie — accessToken for staff and customerAccessToken for customers. That fallback exists for the first-party web apps. A server-side integration should always send the header.

Revocation

Tokens carry a tokenVersion. Logging out and resetting a password both bump it, which invalidates every outstanding token for that account at once. Treat a 401 on a previously working token as a signal to re-authenticate rather than to retry.

Logging in

Use POST /api/v1/auth/refresh-token to exchange a refresh credential for a new access token, and GET /api/v1/auth/me to read the authenticated profile.

Behaviour worth knowing

POST /auth/logout does not reliably end other sessions. It bumps tokenVersion only when the request carries a token that still verifies. With an expired access token, or with only the refresh cookie, the cookies are cleared but other live sessions survive. Do not present this endpoint as “log out of all devices”.
  • POST /auth/forgot-password always returns 200, including for an address with no account. This is deliberate: a 404 would let the endpoint be used to discover which addresses are registered. Do not branch on 404, and do not report “email sent” as a fact.
  • It is rate limited per IP and per email address at 5 per hour, so a user retrying one address hits 429 sooner than the IP limit alone would suggest.
  • POST /auth/reset-password revokes every session and does not log the user in. Send them to the login screen afterwards.
  • GET /auth/verify-reset-password-token does not consume the token, so a form can safely check it before collecting the new password.