Authentication
API keys, the X-API-Key header, and how the shop scope is enforced.
Every /v1 request must carry an X-API-Key header. nspay resolves
the key, binds the request to the shop the key was issued for, and
refuses anything that doesn't match.
X-API-Key: nspay_live_…How the gateway validates the key
| Condition | HTTP response |
|---|---|
| Header missing | 401 Unauthorized — x-api-key header is required |
| Header present but unknown / revoked | 401 Unauthorized — invalid api key |
| Header valid, scope matches | request proceeds |
The validation runs before any other request parsing — an unauthenticated request is rejected without ever reaching the dispatcher.
Scope enforcement
A resolved API key fixes both merchant_id and shop_id for the
request. Per endpoint:
POST /v1/paymentandPOST /v1/payout— body's merchant/shop scope comes from the key. Do not send scope fields in the body.POST /v1/confirm_paymentandPOST /v1/get_operation_state— operations that belong to a different shop come back as404 Not Found. The gateway never confirms the existence of another shop's operation.
The pattern is the same everywhere: the API key is the source of truth for "which shop is this?".
Issuing and rotating keys
API keys are managed in the admin UI (Shops → API keys):
- Issue a key for a shop — the plaintext token is shown once; it is not stored on the server (only a hash is kept). Copy and store it in your secret manager immediately.
- Revoke a key at any time — subsequent requests using it return
401 Unauthorized. Existing in-flight operations are unaffected.
Treat keys as bearer credentials: anyone with the plaintext value can act as the shop. Use distinct keys per environment, and rotate periodically (issue a new key → roll integrations → revoke the old one).
Examples
# Plain header on a JSON request
curl -X POST https://api.nspay.tech/v1/payment \
-H "Content-Type: application/json" \
-H "X-API-Key: nspay_live_…" \
-d '{ "merchant_operation_id": "…", "client_id": "…",
"method": "WT_RUB_PHONE", "amount": "1500.00",
"currency": "RUB" }'# Multipart confirm with receipt — same header, different body type
curl -X POST https://api.nspay.tech/v1/confirm_payment \
-H "X-API-Key: nspay_live_…" \
-F 'operation_id=…' \
-F 'confirmation_type=receipt' \
-F 'receipt=@/path/to/receipt.pdf;type=application/pdf'The header is case-insensitive on the wire; the docs use the
X-API-Key form everywhere.
Health checks
The gateway's GET /livez, GET /healthz, GET /readyz are
unauthenticated — they return 204 No Content when healthy and
503 Service Unavailable otherwise, and are safe to wire into a
probe without an API key. Everything under /v1 requires the
header.