Authentication
Two-credential token flow — apiKey + secretKey → Bearer access token.
Authentication is a two-credential flow. You exchange your apiKey + secretKey pair for a short-lived Bearer access token, then send that token on every API call. Requiring both halves of the pair means a single leak (e.g. a stray log line, a shared screen) doesn't hand an attacker a working credential.
Your credentials
Each merchant gets two pairs — one for sandbox, one for production:
| Key kind | Prefix | Allowed usage |
|---|---|---|
| Secret · production | sk_live_… | Server-side only. Full access. |
| Secret · sandbox | sk_test_… | Server-side only. Sandbox cascade. |
| Publishable · production | pk_live_… | Browser/native client. Hosted checkout only. |
| Publishable · sandbox | pk_test_… | Browser/native client. Sandbox checkout only. |
secretKey grants full API access. Store it in a secret manager — never commit it or expose it in client-side code. If a key is exposed, rotate the pair from your dashboard.Exchange for a token
Send both keys to POST /api/v1/auth/token. Both must come from the same environment (test pair or live pair) — pairing them across environments returns 401.
curl -X POST https://sandbox.key2pays.com/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{
"apiKey": "pk_test_…",
"secretKey": "sk_test_…"
}'{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp…",
"tokenType": "Bearer",
"expiresIn": 3600,
"environment": "sandbox",
"merchant": { "id": "MCH-001", "name": "Acme Inc" }
}Use the token
Send the accessToken as a Bearer on every other request:
curl https://sandbox.key2pays.com/api/v1/ping \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp…"
Token lifetime + refresh
Access tokens are valid for 1 hour. POST /auth/token returns a long-lived refreshToken alongside the access token — exchange it at POST /auth/refresh for a fresh access token (and a rotated refresh token) without sending your apiKey + secretKey across the wire again.
curl -X POST https://sandbox.key2pays.com/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{ "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp…" }'{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp…",
"tokenType": "Bearer",
"expiresIn": 3600,
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp…",
"refreshExpiresIn": 2592000,
"environment": "sandbox"
}Refresh tokens are valid for 30 days and rotate on every use — each /auth/refresh call returns a new refresh token, invalidating the old one implicitly. Refresh tokens cannot be used to call business endpoints (you'll get 401 invalid_api_key); they only redeem at /auth/refresh.
Legacy raw-key auth
For backward compatibility you can still pass a raw sk_test_… / sk_live_… directly in the Authorization header — the API will accept it as the Bearer. New integrations should prefer the token flow above because it lets you rotate the underlying secret without revoking outstanding sessions.