NRVEPay / API v1

Build your first
bank payment.

Create a payment session, send your customer to hosted checkout, then confirm the result on your server.

01 / Get started

  1. Obtain merchant access and a store-scoped test API key through your merchant account.
  2. Create a session from your server. Keep the API key out of browser code.
  3. Redirect the customer to the returned checkout_url.
  4. Confirm COMPLETED through an authenticated status check or a verified completion webhook before fulfilling the order.
Examples use https://YOUR_NRVE_HOST. Replace it with your deployed NRVEPay base URL. Test keys use the sandbox provider; live access requires merchant and provider approval.

Authentication & scopes

Send your key as a Bearer token with each API request. Test and live keys are separate; store the key securely on your server.

Authorization: Bearer nrve_test_YOUR_KEY
Content-Type: application/json
ScopePurpose
payments:writeCreate sessions and payment links
payments:readRetrieve sessions, list links and inspect request logs
webhooks:manageRegister, list or disable webhook endpoints

Create a payment session

POST /v1/payment-sessions · payments:write

curl 'https://YOUR_NRVE_HOST/v1/payment-sessions' \
  -H 'Authorization: Bearer nrve_test_YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: order-1842-attempt-1' \
  --data '{
    "amount_minor": 7999,
    "currency": "GBP",
    "reference": "ORDER-1842",
    "return_url": "https://merchant.example/complete",
    "cancel_url": "https://merchant.example/cancel"
  }'
FieldRequirements
amount_minorPositive integer in pence; maximum 10,000,000. Use 7999 for £79.99.
currencyGBP only; defaults to GBP.
referenceRequired; 1–18 characters.
return_url / cancel_urlRequired public URLs accepted by the outbound URL safety checks. Use HTTPS in production.
order_idOptional; 1–100 characters.
itemsProvider-dependent product details. Required where your configured provider needs item-level information; confirm during integration onboarding.

Example response · 201 Created

{
  "id": "pay_example",
  "status": "CREATED",
  "checkout_url": "https://YOUR_NRVE_HOST/pay/pay_example",
  "replayed": false
}

Use a stable idempotency key for retries of the same order attempt (at least 8 characters). Replays return HTTP 200 with replayed: true. A different payload using an existing key can return HTTP 409.

Retrieve the payment

GET /v1/payment-sessions/:id · payments:read

{
  "id": "pay_example",
  "order_id": "order_example",
  "status": "COMPLETED",
  "provider_status": null,
  "provider_payment_id": null,
  "amount": 79.99,
  "currency": "GBP"
}

The retrieval response uses amount in pounds; creation above uses amount_minor in pence. Provider fields may be null.

Receive and verify webhooks

POST /v1/webhook-endpoints · webhooks:manage

{
  "url": "https://merchant.example/webhooks/nrvepay",
  "events": ["payment.completed", "payment.failed", "payment.cancelled"]
}

Store the returned signing_secret securely. Endpoints can also subscribe to payment.updated. List endpoints with GET /v1/webhook-endpoints; disable one using DELETE /v1/webhook-endpoints/:id.

Signature verification · Node.js

Capture the exact raw request body before parsing JSON. The signature is a hex HMAC-SHA256 of timestamp + "." + rawBody.

import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyWebhook(rawBody, timestamp, signature, secret) {
  if (!/^\d+$/.test(timestamp || '')) return false;
  if (!/^[a-f0-9]{64}$/i.test(signature || '')) return false;
  const age = Math.abs(Date.now() / 1000 - Number(timestamp));
  if (age > 300) return false;
  const expected = createHmac('sha256', secret)
    .update(timestamp + '.')
    .update(rawBody)
    .digest();
  return timingSafeEqual(expected, Buffer.from(signature, 'hex'));
}

Read X-NRVE-Pay-Timestamp, X-NRVE-Pay-Signature and X-NRVE-Pay-Delivery. The five-minute tolerance above is an integration recommendation; keep your server clock accurate. Deduplicate delivery IDs and payment fulfilment, save the event durably, then respond with a 2xx status. Failed deliveries are retried with backoff up to the configured attempt limit.

A browser return is not proof of payment. Verify the webhook and completed payment state, or retrieve the payment through the authenticated API. Pending or authorised payments must not trigger fulfilment.

Handle payment states deliberately

StateYour application
CREATEDOffer the hosted checkout URL.
CUSTOMER_REDIRECTED, AUTHORISED, SUBMITTED, PENDINGAwait final confirmation. Do not fulfil.
COMPLETEDConfirm amount and order, then fulfil once.
FAILED, CANCELLED, EXPIREDShow a clear outcome and arrange a new attempt where appropriate.

Refunds are merchant-initiated bank transfers. NRVEPay records the refund for reconciliation; it does not execute an automatic refund transfer.

Errors & safe retries

HTTPTypical errorNext step
400invalid_request, idempotency_key_requiredCorrect fields or include the session idempotency key.
401 / 403unauthorized, insufficient_scopeCheck your key and permissions.
402billing_suspendedResolve merchant billing before creating payments.
404not_foundCheck the payment ID and authenticated store.
409idempotency_conflictDo not reuse a key for a different payment.
429 / 5xxRate limit or service failureBack off and inspect payment state before retrying.
503no_eligible_providerCheck provider readiness and required product details.

Inspect recent API calls with GET /v1/developer/logs. Keep payment IDs and request IDs for diagnosis; keep API keys and signing secrets out of logs.

Before you go live

  • Complete merchant approval, store activation and provider onboarding.
  • Confirm pricing, bank account details and any provider-specific product requirements.
  • Use a live API key on your server and register the live webhook endpoint.
  • Test completed, pending, failed and cancelled outcomes, plus duplicate webhook delivery.
  • Confirm that a browser return alone cannot fulfil an order.
Apply for merchant access ↗