neo-pays

Authentication

Every /v1/* route authenticates with an API key:

Authorization: Bearer sk_live_...

X-API-Key: sk_live_... is accepted identically, for HTTP clients that reserve Authorization for something else.

Test keys and live keys

Prefix Mode Real money
sk_test_… Test No — all the code runs (routing, fees, validation), no money moves
sk_live_… Production Yes

Objects created in test mode carry is_test: true and never appear in your production reports.

Test mode does not cover instant payment. The PI and tontine families refuse test keys: they talk to an external system that has no sandbox on our side.

The secret exists once

When a key is created (or rotated), the secret is shown once. On our side only its HMAC is stored: nobody — not even support — can give it back to you. Lost? Rotate: the old key is revoked and the new one is shown once.

Why does my key answer client_inactive?

A key is issued as soon as you sign up, but it admits no call until the account is approved (KYB file accepted, account active). That is the compliance door: it opens on approval and closes immediately on suspension — the same key, with nothing else changed.

Scopes

Each key carries scopes, and an operation outside them answers 403 insufficient_scope: collect, pay out, refund, read, manage webhooks. Issue the narrowest key that does the job — a read key for your reports has no business being able to pay out.

Idempotency

On creations (POST /v1/payments, POST /v1/payouts, POST /v1/refunds…), pass an Idempotency-Key header of your choosing — your order reference, for instance. A replay with the same key returns the original operation, never a duplicate; the same key with a different payload is refused with 409.

One key per operation, never per parent object. A collection can be refunded in several parts: an idempotency key carrying the payment's identifier would make the second partial refund look like a replay of the first. Success on the merchant's side, customer not refunded.

Rate limit

300 requests per minute per key. Beyond that, 429 with a Retry-After header — honour it rather than retrying immediately.

Good practice

  • One key per environment (production, staging), never shared between services.
  • The secret lives in a secret manager, never in code and never in the front end.
  • Rotate at the first doubt — with no outage if you deploy the new key before revoking the old one.