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.
| Prefix | Mode | Where it lives | Can do |
|---|---|---|---|
| sk_test_… | Test | Server only | Everything |
| sk_live_… | Live | Server only | Everything |
| pk_test_… | Test | Browser / mobile | Retrieve checkout sessions only |
| pk_live_… | Live | Browser / mobile | Retrieve checkout sessions only |
Secret keys never touch the browser
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 and should call the www host directly.
curl https://www.lunipay.io/api/v1/customers \
-H "Authorization: Bearer sk_test_YOUR_KEY"Use www.lunipay.io for API calls
https://www.lunipay.io/api/v1. Do not call https://lunipay.io/api/v1 from code. The apex domain can redirect to www, and most HTTP clients dropAuthorization when a redirect crosses hosts.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.
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.Keys are scoped to the environment
www.lunipay.io, and hosted LuniPay keys will not authenticate against your local instance. If you see invalid_key, check both the key prefix and the API host.Authentication errors
If the Authorization header is missing or malformed, LuniPay returns 401 missing_key. The error body follows the standard shape:
{
"error": {
"type": "authentication_error",
"code": "missing_key",
"message": "Missing or malformed Authorization header. Expected: Bearer {api_key}. Use https://www.lunipay.io/api/v1 directly; requests to lunipay.io may redirect and lose the Authorization header."
}
}If the header is present but the key does not belong to this environment, LuniPay returns 401 invalid_key.
{
"error": {
"type": "authentication_error",
"code": "invalid_key",
"message": "Invalid API key provided. Check that the key belongs to this LuniPay environment and API host."
}
}