Authorization header:
X-API-Key: <token> is accepted as an alternative header.
Credential types
- JWT session (users with login)
- API key (server to server)
Obtained from Company accounts can have multiple members with roles — see
company members below.
POST /v1/auth/register or POST /v1/auth/login, valid for
24 hours. Meant for apps where users sign in. Along with the
access_token you receive a refresh token to renew the session without
asking for the password again — see
session renewal.If the account’s policy requires OTP on login, the response carries
otp_required: true with a pending_token instead of the session: the
second step completes at POST /v1/auth/login/otp with the code received
over SMS/WhatsApp. Full flow in security and 2FA.You can also offer sign up and sign in with Google, Apple, Microsoft or
Facebook (passwordless) — see social login.
Session renewal (refresh tokens)
Theaccess_token lasts 24 hours; the refresh_token (rt_…) lets you get
a fresh pair without re-login for 30 days, renewed on every use up to a
maximum of 90 days from the original login. It is single-use: every
exchange returns a new refresh_token and invalidates the previous one
(rotation).
- Strict rotation: on exchange, the previous access token of that device is revoked immediately (only one live access token per chain). Always replace BOTH tokens with the ones in the response.
- Reuse = theft: if an already-exchanged refresh token is presented
again, the device’s entire chain is revoked (tokens and sessions) and a
refresh_token_reuseevent is recorded inGET /v1/me/security/events. The user must sign in again. - Dies with the session: signing out (
DELETE /v1/me/sessions/{id}),POST /v1/me/sessions/revoke-allor a password change/reset also invalidate the associated refresh tokens. - Every rejection returns
401 invalid_refresh_token— on that error, send the user to the login screen. - Store the refresh token in secure storage (Keychain/Keystore on mobile; on
web, prefer memory + re-login or an httpOnly cookie from your backend).
pk_API keys do not use refresh: they never expire.
How often should I refresh?
How often should I refresh?
When the access token is about to expire (use
expires_at) or upon a 401
on a normal call. Avoid refreshing in parallel from several places: if two
exchanges of the same token race, one wins and the other gets a 401
without penalty — but exchanging a token that was ALREADY rotated revokes
the chain.What happens after 90 days?
What happens after 90 days?
The chain’s absolute cap is 90 days from the original login: even refreshing
daily, once the limit is reached the refresh returns
401 and the user must
authenticate again (password, passkey or social login).Does refresh work with API keys?
Does refresh work with API keys?
Not applicable:
pk_ API keys never expire and have no session. Refresh is
only for JWT sessions of human users.Access level
Your credential (session JWT or API key) operates your own account: balances, payouts, payins, transfers, crypto, KYC/KYB and your own webhooks. If an endpoint responds403 account_required or 403 org_admin_required,
that operation belongs to a different credential level — contact the CBPay
team.
Your account profile
PATCH /v1/me accepts display_name, tax_id, phone and country
(send only the ones that change). email, status and kyc_status are
not self-managed: the administrator resolves them.
Company members
Company accounts can have multiple users with their own login and different permission levels:POST /v1/members responds 403 company_only.
Best practices
- Store API keys in a secrets manager; never in code or in the browser.
- Use one key per environment/service (descriptive
label) so you can rotate without downtime.
1
Zero-downtime rotation
Issue the new key with
POST /v1/api-keys (new label).2
Deploy
Update your service to use the new key.
3
Retire the old one
Ask the CBPay team to revoke the previous key once traffic migrated.
- JWT sessions are for front-ends; automated processes should always use API keys.