status.
Setting up webhooks
Configure your webhook URL in the Merchant Dashboard → Settings → Developer → Webhooks:- Add your webhook endpoint URL
- Select the events you want (or subscribe to all with
"*") - Your signing secret is generated — save it securely (you can view it again anytime via a verification code)
Your signing secret verifies that incoming webhooks are genuinely from Numero. Keep it private and never expose it in client-side code.
How webhooks work
Envelope
Every delivery is aPOST of this structure:
| Field | Type | Description |
|---|---|---|
id | string | Unique delivery id — use it to dedupe (the same event may arrive more than once) |
event | string | The event type (see below) |
created_at | string | ISO 8601 timestamp |
data | object | Event-specific payload (schemas below) |
data use the API’s camelCase field names.
Headers
| Header | Description |
|---|---|
Content-Type | application/json |
X-Numero-Signature | t=<timestamp>,v1=<base64 HMAC-SHA256> — see Signature Verification |
X-Webhook-Id | Unique delivery id (also in the body as id) |
X-Webhook-Event | The event type |
Event types
| Event | Fires on | Success | Failure | data schema |
|---|---|---|---|---|
FUNDING_NOTIFICATION | Inbound credit lands (VA funding, settlement) and internal-transfer receipt | ✓ | n/a¹ | TransactionWebhookData |
TRANSFER_NOTIFICATION | Outbound bank transfer settles and internal-transfer send | ✓ | ✓ | TransactionWebhookData |
PAYOUT_NOTIFICATION | International payout settles | ✓ | ✓ | TransactionWebhookData |
BILLS_PURCHASE_NOTIFICATION | A bill payment (airtime/data/electricity/cable/betting) settles | ✓ | ✓ | BillsPurchaseWebhook |
VERIFICATION_NOTIFICATION | A verification settles out of Pending | ✓ | ✓ | VerificationWebhookData |
VIRTUAL_ACCOUNT_CREATED | A customer/business virtual account is minted | ✓ | n/a² | VirtualAccountCreatedData |
CURRENCY_CONVERSION | An FX conversion completes | ✓ | n/a² | CurrencyConversionData |
status: false + a 4xx/503), so there’s nothing to webhook. Branch on the call’s own response for those.
Determine the outcome fromdata.status(Successful/Unsuccessful/Pending) anddata.requestState/data.requestStateDetails— don’t infer it from the event type. A failed outbound transfer/payout fires withstatus: "Unsuccessful"andrequestState: "Failed"; the debit is returned to your wallet through the reversal workflow.
Payloads
TransactionWebhookData — money movement (transfer / funding / payout / internal)
All amounts are in naira.
| Field | Type | Description |
|---|---|---|
reference | string | Transaction reference |
type / service | string | Transaction type and service |
direction | string | CREDIT or DEBIT |
status | string | Successful · Unsuccessful · Pending |
requestState / requestStateDetails | string | Processing state + detail |
trxAmount | number | Amount (naira) |
trxFee | number | The fee charged on this transaction (naira) |
stampDutyApplied / stampDutyAmount | bool / number | Stamp duty, when applicable |
balanceBefore / balanceAfter | number | Wallet balance around the event |
beneficiaryName / beneficiaryNumber / beneficiaryBank | string | The payer (on credits) |
toAccountName / toAccountNumber / toAccountBank | string | The recipient (on debits) |
merchant / businessCode | string | Your business |
isReversed | bool | Whether the transaction was reversed |
token | string | Utility token, when applicable |
dateCreated / dateModified | string | Timestamps |
BillsPurchaseWebhook — VAS
| Field | Type | Description |
|---|---|---|
vertical | string | AIRTIME · DATA · ELECTRICITY · CABLETV · BETTING |
status | string | Successful · Failed |
customerIdentifier | string | Phone / meter / smartcard / betting id |
token | string | Utility token (electricity), when applicable |
VerificationWebhookData
| Field | Type | Description |
|---|---|---|
type | string | e.g. BVN, NIN, CAC_ADVANCED |
status | string | Completed · Failed |
businessCharge | number | Naira charged (null if not charged) |
VirtualAccountCreatedData
| Field | Type | Description |
|---|---|---|
type | string | customer or business |
customerEmail | string | null for business VAs |
CurrencyConversionData
Field names follow the API’s camelCase, but the webhook body uses a different serializer than the request/response API — confirm exact casing against a live delivery while integrating.
Retries
- Respond
2xxto acknowledge. Any non-2xx (or a timeout) is a failed delivery. - Every webhook is persisted before delivery, so events are never lost if your endpoint is down.
- Failed deliveries are retried automatically with exponential backoff for up to 24 hours, and can be re-sent manually from the dashboard. After 10 consecutive failures the subscription is disabled.
- Emission is fire-and-forget on our side — a webhook problem never unwinds the underlying money movement.