Webhooks
Receive events (e.g. transaction status changes) at your endpoint. Configure Endpoint URL and Secret in the dashboard: Organization → API & Webhooks. We send a signed JSON body and headers you can verify.
Headers
Every webhook request includes:
| Header | Description |
|---|---|
Content-Type | application/json |
X-Webhook-Event | Event type (e.g. transaction.status_changed, webhook.test) |
X-Webhook-Delivery-Id | Unique delivery ID (UUID) |
X-Webhook-Timestamp | Unix timestamp (seconds) |
X-Webhook-Signature | sha256=<hex_hmac> — see Verifying signatures |
Verifying signatures
We sign the raw request body with HMAC-SHA256 using your webhook secret. Verify as follows:
- Read the raw body of the request (as bytes / string, before parsing JSON).
- Compute
HMAC-SHA256(raw_body, your_webhook_secret)and get the hex digest. - Compare it to the value in
X-Webhook-Signatureafter thesha256=prefix.
Important: Use the exact raw body. Do not re-serialize parsed JSON (key order or formatting may differ).
Example (Node.js)
const crypto = require('crypto');
function verifySignature(rawBody, signatureHeader, secret) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));
}
Example (Python)
import hmac
import hashlib
def verify_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature_header, expected)
Event: transaction.status_changed
Sent when a transaction’s status changes (paid, failed, refund_pending, refunded, canceled, etc.).
Payload:
{
"event": "transaction.status_changed",
"transaction_id": "TXabc123",
"amount": "99.00",
"status": "paid",
"currency": "USD",
"created_at": "2026-03-01T12:00:00Z",
"updated_at": "2026-03-01T12:01:00Z"
}
| Field | Description |
|---|---|
transaction_id | Public transaction ID (e.g. for GET /api/transactions/) |
amount | Net amount (after fees) |
status | Current status (e.g. paid, failed, refunded, refund_pending, canceled) |
currency | Currency code |
created_at / updated_at | ISO 8601 timestamps |
Test event
Use Send test event in Organization → Webhooks to send a webhook.test payload to your endpoint. Your endpoint should respond with 2xx to confirm delivery. The payload is:
{
"event": "webhook.test",
"message": "Test delivery from ND8"
}
Secret rotation
Rotate your webhook secret in Organization → API & Webhooks. After rotation, only the new secret is shown once; previous signatures will no longer verify. Update your endpoint to use the new secret immediately.