Authentication
Bearer tokens, scopes, live vs test mode, and key rotation.
Overview
Every Partner API call authenticates with a bearer token in the Authorization header. Tokens are partner-scoped, prefixed by mode (live or test), and optionally restricted to a subset of endpoints via scopes. There is no OAuth, no token refresh, no session state.
Bearer token
Send your API key in the Authorization header on every request:
Authorization: Bearer jo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxMissing, malformed, unknown, or revoked keys return 401 unauthorized. Keys are validated per-request against the partner's key table; revoking a key takes effect on the next request, no cache warmup required.
/portal/api-keys) and generate a new one immediately.Base URL
Call the API at one of two hosts. Both serve identical routes and data:
https://<partner-slug>.jopay.app— most partners call from their own subdomain so branding context is preserved end-to-endhttps://admin.jopay.app— available for partners without a subdomain
Scopes (restricted keys)
By default a new key can call every v1 endpoint. You can restrict a key to a subset of endpoints by selecting scopes when you create it. Use restricted keys for CI, read-only dashboards, or integrations that should only touch a subset of resources.
| Scope | Endpoints |
|---|---|
requests:read | GET /api/v1/requests, GET /api/v1/requests/:id |
requests:write | POST /api/v1/requests/create, POST /api/v1/requests/:id/cancel |
merchants:read | GET /api/v1/merchants, GET /api/v1/merchants/:id |
merchants:write | POST /api/v1/merchants |
Handling 403 insufficient_scope
Calling an endpoint the key isn't scoped for returns 403 insufficient_scope. The response body tells you exactly which scope is missing:
{
"ok": false,
"error": "insufficient_scope",
"required_scope": "requests:write"
}Add the missing scope to the existing key in the partner portal, or generate a new key with broader scope. Restricted keys are not upgraded by JoPay — you always swap keys, never mutate a deployed key's scope silently.
Live and test mode
Every key is exactly one of two modes. The prefix is authoritative:
jo_live_…— hits production data. Every request and merchant created by a live key is real.jo_test_…— hits sandbox data, fully isolated from live. Test-mode requests are taggedtest_mode: truein every response, filtered out of live views, and never visible to live keys.
A live key and a test key behave identically at the auth layer; the difference is the data they see. Use test keys in CI, staging, and integration tests so a buggy deploy can't accidentally create real payment requests.
You cannot mix modes in one call: a test key used against a live merchant (or vice versa) returns 400 merchant_mode_mismatch.
jo_test_ key for CI and staging, a jo_live_ key for production. Loading the wrong key into the wrong environment then fails at the auth layer with a clear error, not silently.Rotating keys
Rotation is a two-step swap, not an in-place mutation:
- Create a new key in the partner portal with the same scopes as the old one.
- Deploy the new key to your environment. The old key continues to work until you revoke it.
- Once the new key is live and handling traffic, revoke the old one.
There is no "rotate in place" endpoint. Every key has a stable identity from creation to revocation; this makes audit trails and incident forensics unambiguous.
Other auth types (for reference)
The Partner API (/api/v1/*) is the only surface partner-side code touches. For completeness, JoPay uses three other authentication models internally:
| Auth type | Used by |
|---|---|
| Admin session | Cookie-based session for the admin.jopay.app panel. JoPay staff only. |
| Merchant session | Cookie-based session for the merchant dashboard. Merchants authenticate via Sequence; the session cookie is set server-side. |
| Cron secret | Shared secret in the Authorization header for scheduled-job endpoints. Not callable from partner or merchant contexts. |
These are listed only so you recognize them if they appear in logs or error messages. Your code never sends or receives them.