Webhooks
Events & signatures
Configure your HTTPS endpoint and event subscriptions in the dashboard. NeratPay signs the exact raw body with HMAC-SHA512.
Header
x-neratpay-signature — hex digest of HMAC-SHA512(rawBody, webhookSecret).
Read the raw bytes first, verify, then parse JSON. The API secret will not verify the signature — use the webhook secret from Developers.
Events
| Event | Meaning |
|---|---|
payment.successful | Deposit succeeded (pair with credited) |
virtualaccount.credited | Same deposit — credit your user once |
virtualaccount.active | Account number ready (Paystack/test; also sent for PalmPay) |
transfer.completed | Payout succeeded |
transfer.failed | Payout failed; amount available again |
payment.failed | Reserved — a transfer that never arrives does not send this |
Every event includes top-level livemode. It is false for test-mode events.
Example payload
{
"event": "payment.successful",
"livemode": true,
"sentAt": "2026-10-18T12:00:00.000Z",
"data": {
"customerReference": "user-42",
"transaction": {
"id": "6712...",
"reference": "palmpay-order-id",
"amount": 2500,
"fee": 0,
"currency": "NGN",
"status": "successful",
"provider": "palmpay"
}
}
}
Delivery & retries
Tried once immediately. If your server does not answer 2xx within 8 seconds, NeratPay retries after 1 minute, 5 minutes, 30 minutes, and 2 hours, then stops. Answer 2xx after you have stored the event — including when you already processed that reference.
Verify (Node)
const crypto = require('crypto');
function verifyNeratPay(rawBody, signature, secret) {
if (!signature || !secret) return false;
const expected = crypto.createHmac('sha512', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(String(signature));
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}
Verify (Python)
import hmac, hashlib
def verify_neratpay(raw_body: bytes, signature: str, secret: str) -> bool:
if not signature or not secret:
return False
expected = hmac.new(secret.encode(), raw_body, hashlib.sha512).hexdigest()
return hmac.compare_digest(expected, signature)