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
- Obtain merchant access and a store-scoped test API key through your merchant account.
- Create a session from your server. Keep the API key out of browser code.
- Redirect the customer to the returned
checkout_url. - Confirm
COMPLETEDthrough an authenticated status check or a verified completion webhook before fulfilling the order.
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| Scope | Purpose |
|---|---|
payments:write | Create sessions and payment links |
payments:read | Retrieve sessions, list links and inspect request logs |
webhooks:manage | Register, 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"
}'| Field | Requirements |
|---|---|
amount_minor | Positive integer in pence; maximum 10,000,000. Use 7999 for £79.99. |
currency | GBP only; defaults to GBP. |
reference | Required; 1–18 characters. |
return_url / cancel_url | Required public URLs accepted by the outbound URL safety checks. Use HTTPS in production. |
order_id | Optional; 1–100 characters. |
items | Provider-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.
Create a Payment Link
POST /v1/payment-links · payments:write
{
"title": "Order 1842",
"amount_minor": 7999,
"currency": "GBP",
"reference": "ORDER-1842",
"return_url": "https://merchant.example/complete",
"cancel_url": "https://merchant.example/cancel"
}The response includes id, url, status, amount_minor, currency, environment and expires_at. Share the returned URL. Optional fields include a description (up to 500 characters), an ISO date-time expires_at and provider-specific items.
GET /v1/payment-links returns up to 100 recent links for the authenticated store. Link creation does not implement the session endpoint’s idempotency header; avoid blindly retrying a create-link request after an uncertain response.
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.
Handle payment states deliberately
| State | Your application |
|---|---|
CREATED | Offer the hosted checkout URL. |
CUSTOMER_REDIRECTED, AUTHORISED, SUBMITTED, PENDING | Await final confirmation. Do not fulfil. |
COMPLETED | Confirm amount and order, then fulfil once. |
FAILED, CANCELLED, EXPIRED | Show 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
| HTTP | Typical error | Next step |
|---|---|---|
| 400 | invalid_request, idempotency_key_required | Correct fields or include the session idempotency key. |
| 401 / 403 | unauthorized, insufficient_scope | Check your key and permissions. |
| 402 | billing_suspended | Resolve merchant billing before creating payments. |
| 404 | not_found | Check the payment ID and authenticated store. |
| 409 | idempotency_conflict | Do not reuse a key for a different payment. |
| 429 / 5xx | Rate limit or service failure | Back off and inspect payment state before retrying. |
| 503 | no_eligible_provider | Check 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.