Authentication
All PayKore API requests are authenticated with an API key. Keys are issued per partner account and scoped to a single environment.
API Keys
PayKore issues two classes of keys:
| Type | Prefix | Use |
|---|---|---|
| Secret key | sk_live_ / sk_test_ | Server-side API calls. Never expose publicly. |
| Publishable key | pk_live_ / pk_test_ | Future client-side SDK initialisation (not yet available). |
At MVP, all API calls use secret keys and must be made server-side. A secret key looks like this:
sk_test_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
That's a sk_test_ or sk_live_ prefix followed by 64 hex characters (256 bits of entropy).
PayKore shows the full key once at creation. Copy it immediately and store it in your secrets manager. If you lose it, you must revoke and replace it — there is no "reveal key" option.
Sending your API key
Two formats are accepted. Use Method 1.
# Method 1: X-API-Key header (preferred — explicit and unambiguous)
curl https://api.paykore.dev/v1/wallets \
-H "X-API-Key: sk_test_YOUR_KEY_HERE"
# Method 2: Bearer token (also accepted)
curl https://api.paykore.dev/v1/wallets \
-H "Authorization: Bearer sk_test_YOUR_KEY_HERE"
Method 1 (X-API-Key) is preferred. It makes it immediately clear in logs and code reviews that a PayKore key is being used, and avoids ambiguity with other Bearer tokens in the same service.
Environments and key isolation
Keys are strictly scoped to their environment. There is no crossover.
| Key prefix | Works against | Fails against |
|---|---|---|
sk_test_* | Sandbox data | Live data |
sk_live_* | Live data | Sandbox data |
Using a live key against the sandbox API returns 401 INVALID_API_KEY. Using a test key against live data does the same. This is intentional — it prevents accidental production writes during development.
Keep your sandbox and live keys in separate environment variables: PAYKORE_API_KEY_SANDBOX and PAYKORE_API_KEY_LIVE. Load the right one based on NODE_ENV or equivalent. Never swap them with a boolean flag — use distinct variable names.
Error responses
All auth errors return HTTP 401 with a structured JSON body.
No key provided:
{
"error": {
"code": "MISSING_API_KEY",
"message": "No API key was provided. Add an X-API-Key header.",
"http_status": 401
},
"meta": {
"request_id": "req_4kMnO5pQrS"
}
}
Key not found or revoked:
{
"error": {
"code": "INVALID_API_KEY",
"message": "The API key provided is invalid or has been revoked.",
"http_status": 401
},
"meta": {
"request_id": "req_7hJkL9mNpQ"
}
}
Key past its expiry date:
{
"error": {
"code": "EXPIRED_API_KEY",
"message": "This API key expired on 2025-01-01. Create a new key in the dashboard.",
"http_status": 401
},
"meta": {
"request_id": "req_2bCdE3fGhI"
}
}
Every error response includes meta.request_id. Include this ID in any support request — it maps to the exact request in PayKore's logs.
Security best practices
Violating any of these rules can expose your users' funds to theft. Treat your secret key with the same care as a database root password.
-
Never hardcode keys in client-side code. Any key in JavaScript, a React app, or a mobile bundle is readable by anyone who downloads your app.
-
Never commit keys to Git. Use environment variables. Add
.envto.gitignore. If a key is committed, assume it is compromised — revoke it immediately, even if the repo is private. -
Use separate keys per environment. One key for local development (optional — use sandbox), one for staging, one for production. This limits blast radius if one key leaks.
-
Rotate immediately if compromised. Go to the dashboard → API Keys → Revoke. Create a new key. Deploy it. There is no "change password" — revoke and replace.
-
Set descriptive labels. When creating a key, label it by service:
api-server-production,worker-staging. This lets you trace usage in the dashboard and revoke targeted keys without disruption. -
Use a secrets manager in production. Store live keys in AWS Secrets Manager, GCP Secret Manager, or Doppler. Pull at runtime. Never bake them into Docker images or deployment configs.
Key rotation without downtime
Rotating a key takes about 5 minutes and requires no downtime:
- Create a new key in the dashboard (Settings → API Keys → Create Key). Give it a label like
api-server-production-new. - Update your environment variable to the new key value.
- Deploy your service. New requests now use the new key.
- Verify in the dashboard that traffic is showing on the new key (API key usage metrics update in real time).
- Revoke the old key in the dashboard.
PayKore caches valid key lookups in Redis for 5 minutes. After you revoke a key, it remains valid for up to 5 minutes while the cache expires. Plan your rotation accordingly — deploy the new key first, then revoke the old one only after confirming the new key is working.
Rate limits
Requests are rate-limited per API key.
| Partner tier | Limit | Burst |
|---|---|---|
| Starter | 300 requests / minute | — |
| Growth | 1,000 requests / minute | — |
| Scale | Custom | Contact us |
Every response includes rate limit headers:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 247
X-RateLimit-Reset: 1717200060
When you exceed the limit, you receive a 429 response:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Slow down and retry after the indicated time.",
"http_status": 429
},
"meta": {
"request_id": "req_9kLmN2oPqR",
"retry_after": 12
}
}
The meta.retry_after value is in seconds. Implement exponential backoff on 429 responses — do not hammer the API at exactly the reset time.
Next steps
- Wallets → — Create and manage user wallets.
- API Key Best Practices → — Deeper security guidance for production deployments.
- Dashboard: Managing API Keys → — How to create, label, and revoke keys in the UI.