Know when money moves.
Receive signed payment events, verify their source and apply each outcome safely.
Configure your application’s receiver
Open API Keys, edit the named key, and save an HTTPS Web Hook URL. Read the separate webhook signing secret from the same dialog using your transactional PIN.
Use a public DNS hostname on port 443, without embedded credentials, query parameters or fragments. Private destinations and redirects are rejected. Delivery uses a three-second connection timeout and ten-second request timeout.
Event shape
{
"id": "event-uuid",
"event": "collection.success",
"livemode": false,
"data": {
"reference": "NPTEXAMPLE01",
"application_id": "application-uuid",
"application_name": "Online store",
"type": "collection",
"status": "success",
"amount": "500.00",
"fee": "20.00",
"gross_amount": "520.00",
"currency": "UGX",
"mode": "test",
"livemode": false,
"version": 1
}
}The actual data object contains the complete payment resource in the OpenAPI schema. Events are collection.process, collection.success, collection.failed, and the corresponding disbursement.* events.
Verify the signature before acting
- Read the exact raw request body and the
X-NuePay-Timestampheader. - Reject timestamps more than five minutes from your synchronized server clock.
- Calculate hexadecimal HMAC-SHA256 of
timestamp + "." + raw_body, keyed by the webhook signing secret. - Use constant-time comparison against
v1=plus the digest inX-NuePay-Signature. - Check the body event ID matches
X-NuePay-Event-Id, then validatelivemode, deduplicate and apply the newest payment version.
import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody must be the unmodified request bytes.
const expected = 'v1=' + createHmac('sha256', signingSecret)
.update(timestamp + '.').update(rawBody).digest('hex');
const supplied = Buffer.from(signatureHeader, 'utf8');
const valid = supplied.length === Buffer.byteLength(expected)
&& timingSafeEqual(Buffer.from(expected), supplied);
// Also validate timestamp, event ID, environment and version.Acknowledge durable receipt
Return any 2xx response after saving the event durably. A lost acknowledgement can cause a duplicate. Non-2xx responses and connection errors retry after 1 minute, 5 minutes, 15 minutes, 1 hour, 4 hours, 12 hours and then 24 hours, up to ten attempts.
Inspect delivery history and PIN-protected retries on API Keys. Pausing an endpoint holds events. API-secret rotation and webhook-secret rotation are separate actions; replacing one does not replace the other.

