Core

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 kindPrefixAllowed usage
Secret · productionsk_live_…Server-side only. Full access.
Secret · sandboxsk_test_…Server-side only. Sandbox cascade.
Publishable · productionpk_live_…Browser/native client. Hosted checkout only.
Publishable · sandboxpk_test_…Browser/native client. Sandbox checkout only.
The 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 /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-api.key2pays.com/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "apiKey":    "pk_test_…",
    "secretKey": "sk_test_…"
  }'
Response 200
{
  "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:

bash
curl https://sandbox-api.key2pays.com/v1/ping \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp…"

Token lifetime

Tokens are valid for 1 hour. When you receive 401 token_expired, request a fresh token from /auth/token with the same key pair. Most clients cache the token in memory and refresh proactively a minute before expiry.

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.