Getting Started

Authentication

Every LuniPay API request is authenticated with a prefixed key over HTTPS. Keep your secret keys on the server, never in a browser or a mobile app.

Key types

LuniPay issues four keys per organization. The prefix tells you at a glance whether a key is secret or publishable, test or live — no database lookup required.

PrefixModeWhere it livesCan do
sk_test_…TestServer onlyEverything
sk_live_…LiveServer onlyEverything
pk_test_…TestBrowser / mobileRetrieve checkout sessions only
pk_live_…LiveBrowser / mobileRetrieve checkout sessions only

Secret keys never touch the browser

A leaked sk_… key gives an attacker full API access to your account. Use publishable keys for any code that runs on a device you do not control, and rotate secrets immediately if you think one has leaked.

Sending a request

Pass the key in the Authorization header as a bearer token. Every request must use HTTPS.

curl https://lunipay.io/api/v1/customers \
  -H "Authorization: Bearer sk_test_YOUR_KEY"

Storing keys

Never commit a secret key to git. Put it in environment variables, a secret manager (Vercel, Doppler, AWS Secrets Manager), or your CI provider's secret store. The secret value is shown exactly once on creation — if you lose it, rotate from the dashboard rather than digging through old logs.

Rotating keys

Rotation is a single click from Settings → Developer. The old key is revoked immediately and a new one is generated. Deploy the new key before rotating, or keep both keys configured for a short window.

Live vs test keys

Test and live modes share the same schema, but no data crosses between them. Every database row carries a livemode boolean; every API response includes it; every query filters on it. Practically that means:

  • A test customer is invisible to live-mode queries and vice versa.
  • A webhook endpoint registered in test mode never fires for live events.
  • Refunds, ledger entries, payouts — everything respects the livemode your key was issued for.
Build and test with sk_test_… keys until you are confident. No real charges ever happen in test mode, and the dashboard shows a bright orange banner so you can always tell which mode you are in.

Authentication errors

If the Authorization header is missing or malformed, LuniPay returns 401 invalid_api_key. The error body follows the standard shape:

{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "Invalid API key provided."
  }
}