Webhooks
Receive real-time notifications for events.
Webhooks
Webhooks let your system receive real-time updates when events happen on Uverus, instead of polling for status.
Headers
| Header | Required | Value |
|---|---|---|
Authorization | Yes | Bearer sk_test_... (test) or Bearer sk_live_... (live) — see Authentication |
Setting Up
You can manage webhook endpoints from Settings → Webhooks in the dashboard, or via the API below. Either way, once an endpoint is registered, Uverus sends a POST request to it whenever a subscribed event occurs.
Register an Endpoint
POST /api/v1/merchant-webhooksRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Your endpoint URL. Must be http(s)://. |
events | string[] | No | Event names to subscribe to. Omit (or pass ["*"]) to receive every event. |
Example Request
curl -X POST "https://api.uveruspayments.com/api/v1/merchant-webhooks" \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{ "url": "https://your-api.com/webhooks/uverus" }'Example Response
{
"id": "uuid",
"merchantId": "uuid",
"url": "https://your-api.com/webhooks/uverus",
"secret": "whsec_...",
"events": "*",
"isActive": true,
"mode": "test",
"successCount": 0,
"failureCount": 0,
"lastDeliveredAt": null,
"createdAt": "2026-08-27T10:00:00.000Z"
}Important
secret is only ever shown in full via this response and in the dashboard. Save it — you'll need it to verify signatures below.
List Endpoints
GET /api/v1/merchant-webhooksReturns every webhook endpoint registered for the authenticated merchant and mode.
Remove an Endpoint
DELETE /api/v1/merchant-webhooks/{id}Send a Test Event
Fires a test.event payload at your endpoint immediately, using the real signing and delivery path — useful for confirming your handler and signature verification work before going live.
POST /api/v1/merchant-webhooks/{id}/testEvent Types
| Event | Description |
|---|---|
checkout.success | A customer completed a checkout payment successfully. |
checkout.failed | A checkout payment failed. |
transfer.success | An outbound transfer was delivered to the recipient. |
transfer.failed | An outbound transfer failed; funds were returned to your Transfer wallet. |
Payload Structure
{
"event": "checkout.success",
"data": {
"reference": "uvr_123456",
"amount": 500000,
"currency": "NGN",
"status": "completed",
"customerEmail": "customer@example.com"
},
"timestamp": "2026-08-27T10:15:00.000Z",
"webhookId": "uuid"
}Every delivery also carries these headers:
| Header | Description |
|---|---|
X-Uverus-Signature | HMAC-SHA256 signature of the raw request body — see below |
X-Uverus-Event | The event name, matching the event field in the body |
X-Uverus-Webhook-Id | The ID of the webhook endpoint that was triggered |
X-Uverus-Attempt | Delivery attempt number (retries up to 3 times on failure) |
Security (HMAC Verification)
Every payload is signed with your endpoint's secret (from registering the endpoint). Verify the X-Uverus-Signature header to confirm a request actually came from Uverus:
const crypto = require('crypto');
const signature = request.headers['x-uverus-signature'];
const expected = crypto
.createHmac('sha256', YOUR_WEBHOOK_SECRET)
.update(rawRequestBody) // the exact raw bytes received — not a re-serialized JSON.stringify(req.body)
.digest('hex');
if (expected === signature) {
// Request is authentic
}Important
Compute the signature over the raw request body, before your framework parses it into an object. Re-serializing a parsed body can reorder keys or change whitespace, producing a signature that never matches.