status.
Setting up webhooks
For API-issued cards, the Virtual Cards group includes private wallet verification codes (card.code). See Card wallet verification for the payload, source-based delivery routing and sensitive-code handling requirements.
Configure your webhook URL in the Merchant Dashboard → Settings → Developer → Webhooks:
- Add your webhook endpoint URL
- Select the services you want. Each checkbox includes every event in that service; individual-event selection is not offered in the dashboard.
- 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:
The envelope and
data use the API’s camelCase field names.
Headers
Event types
¹ An inbound credit has no “merchant failure” to report. ² FX conversion and VA creation are synchronous — a failure is returned in the API response (
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
Additional subscription events
The dashboard also offersBULK_TRANSFER_NOTIFICATION for terminal bulk-transfer batch outcomes and these WAAS events:
These exact, case-sensitive names identify delivered events in both live and test mode. Select WAAS in the dashboard to include every WAAS event. Existing subscriptions retain their selections until you save changes; saving an older individual-event subscription upgrades the selected services to whole groups. Existing API integrations using exact event names or
* remain supported. VIRTUAL_ACCOUNT_RETIRED remains reserved and is not currently emitted.
Service groups
The subscription groups areWAAS, VIRTUAL_CARDS, INVOICES, FUNDING, TRANSFERS, BILLS, VERIFICATIONS, VIRTUAL_ACCOUNTS, PAYOUTS and FX. Selecting a group includes its events, including future events in that service. Service availability and access requirements still apply.
Virtual Cards includes card.created, card.creation_failed, card.funded, card.funding_failed, card.withdrawn, card.withdrawal_failed, card.frozen, card.unfrozen, card.terminated, card.authorization, card.payment, card.refund, card.reversal and card.declined. Closing a card is termination, not deletion of its transaction history.
Invoices includes invoice.created, invoice.updated, invoice.partially_paid, invoice.paid, invoice.cancelled and invoice.expired. These events report recorded lifecycle changes; a due date passing alone is not a payment or a recorded expiry.
Card and invoice lifecycle events are queued in the same database transaction as their source changes, then delivered by the background worker (normally on its next minute cycle). Pending card requests do not emit successful creation or funding events. The payload contains customer-facing references, status, currency and relevant amounts or balances—never card credentials.
Use data.eventId to deduplicate card and invoice lifecycle events; it stays stable across delivery retries. Delivery is at least once, so a retry may reach an endpoint that previously accepted the event. A test event goes only to test subscriptions, including on retry.
The dashboard’s Send test event lets you choose a service. Synthetic non-funding samples carry isSample: true and do not create a real card, invoice or wallet transaction.
TransactionWebhookData — money movement (transfer / funding / payout / internal)
All amounts are in naira.
BillsPurchaseWebhook — VAS
VerificationWebhookData
VirtualAccountCreatedData
CurrencyConversionData
Field casing. The four envelope fields are exactlyid,event,created_atanddata— notecreated_atis snake_case. Everything insidedatais camelCase, matching the rest of the API.
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.
- Webhook delivery never affects the transaction it describes. A failed or refused delivery does not reverse, hold or retry the underlying money movement — treat the webhook as notification, and the transaction status endpoint as the source of truth.