Authentication
API key authentication
All API endpoints (except /health and /checkout/:id/status) require authentication via the X-API-Key header.
bash
curl https://pay.yourdomain.com/api/v1/payments \
-H "X-API-Key: pw_live_abc123..."Single-merchant mode
Set API_KEY in your .env file. All requests use this key.
dotenv
API_KEY=your-secret-api-keyMulti-merchant mode
Each merchant has their own API key, issued through the admin dashboard. The key identifies the merchant, and all orders created with that key are scoped to that merchant.
API keys are stored as HMAC-SHA256 hashes (never in plaintext). If a key is lost, it must be regenerated.
Generating API keys
Via admin dashboard
- Log in at
/admin - Go to Merchants
- Click Create Merchant
- Copy the generated API key — it's shown only once
Via API (admin only)
bash
curl -X POST https://pay.yourdomain.com/api/v1/admin/merchants \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "My Shop",
"webhook_url": "https://myshop.com/webhooks/paywarden"
}'Response:
json
{
"id": "merch_abc123",
"name": "My Shop",
"api_key": "pw_live_xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"api_key_prefix": "pw_live_xxxx",
"created_at": "2025-01-01T00:00:00Z"
}Save the API key now
The full API key is returned only once. Store it securely. If lost, you must generate a new one.
Admin authentication
The admin dashboard uses a separate authentication flow:
bash
# Login
curl -X POST https://pay.yourdomain.com/api/v1/admin/login \
-H "Content-Type: application/json" \
-d '{"password": "your-admin-password"}'
# Response sets an httpOnly JWT cookie
# Subsequent requests include the cookie automaticallyAdmin password is set via ADMIN_PASSWORD in .env. JWT sessions expire after 24 hours.
Error responses
| Status | Code | Meaning |
|---|---|---|
401 | UNAUTHORIZED | Missing or invalid X-API-Key |
403 | FORBIDDEN | Valid key but insufficient permissions |
429 | RATE_LIMITED | Too many requests |
json
{
"error": "Invalid or missing API key",
"code": "UNAUTHORIZED"
}