nspay

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

ConditionHTTP response
Header missing401 Unauthorizedx-api-key header is required
Header present but unknown / revoked401 Unauthorizedinvalid api key
Header valid, scope matchesrequest 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/payment and POST /v1/payout — body's merchant/shop scope comes from the key. Do not send scope fields in the body.
  • POST /v1/confirm_payment and POST /v1/get_operation_state — operations that belong to a different shop come back as 404 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.

On this page