Skip to content

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-key

Multi-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

  1. Log in at /admin
  2. Go to Merchants
  3. Click Create Merchant
  4. 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 automatically

Admin password is set via ADMIN_PASSWORD in .env. JWT sessions expire after 24 hours.

Error responses

StatusCodeMeaning
401UNAUTHORIZEDMissing or invalid X-API-Key
403FORBIDDENValid key but insufficient permissions
429RATE_LIMITEDToo many requests
json
{
  "error": "Invalid or missing API key",
  "code": "UNAUTHORIZED"
}

Released under the BSL 1.1 License.