Skip to main content

Webhook Event Reference

Every PayKore webhook shares the same envelope:

{
"event": "transaction.completed",
"data": { },
"created_at": "2025-06-01T15:00:00Z"
}
FieldDescription
eventThe event type, one of the events documented below.
dataEvent-specific fields. Structure varies by event type; see each section.
created_atISO 8601 timestamp of when PayKore generated the event (not necessarily when your server received it).

transaction.completed

Fires when any transaction, P2P transfer, bank transfer, USSD payment, QR payment, or split payment, reaches completed status.

Triggered by: P2P Transfer, Bank Transfer, USSD Payment, QR Payment, Split Payment.

{
"event": "transaction.completed",
"data": {
"id": "tx_4qYzA1bCdE",
"reference": "order_789",
"type": "p2p_transfer",
"amount_kobo": 500000,
"currency": "NGN",
"fee_breakdown": {
"customer_fee_kobo": 2500,
"platform_fee_kobo": 2500
},
"source_wallet": {
"id": "wlt_9f3kA2mXpQ",
"balance_after_kobo": 497500
},
"dest_wallet": {
"id": "wlt_3pRsT7uVwX",
"balance_after_kobo": 500000
},
"completed_at": "2025-06-01T10:03:00Z"
},
"created_at": "2025-06-01T10:03:01Z"
}

Key fields: id, reference, type, amount_kobo, fee_breakdown, completed_at, source_wallet, dest_wallet.

Recommended action: Look up your order or payout record by reference. Mark it as paid/settled. If dest_wallet matches a wallet you're displaying a balance for in your UI, use balance_after_kobo to update it without an extra GET call.


transaction.failed

Fires when a transaction fails after being accepted, most commonly for bank transfers rejected by the receiving bank, or USSD/QR sessions that fail mid-flow.

Triggered by: Bank Transfer, USSD Payment, QR Payment.

{
"event": "transaction.failed",
"data": {
"id": "tx_8wXyZ1aBcD",
"reference": "payout_456",
"type": "bank_transfer",
"amount_kobo": 1000000,
"failed_reason": "Beneficiary bank rejected: account dormant",
"reversal_status": "reversed",
"reversal_tx_id": "tx_9xYzA2bCdE"
},
"created_at": "2025-06-01T11:01:10Z"
}

Key fields: id, reference, failed_reason, reversal_status (whether the originating wallet was credited back).

Recommended action: Mark the corresponding order/payout as failed in your system. Check reversal_status, if "reversed", the source wallet was already credited back automatically and you don't need to issue a manual refund. Surface failed_reason to your user or support team so they understand why (e.g. "account dormant" vs "insufficient funds").


transaction.reversed

Fires when a previously completed transaction is later reversed, for example, a bank flags a transfer as fraudulent after settlement, or PayKore support processes a manual reversal.

Triggered by: Any completed transaction type, via manual reversal or downstream bank action.

{
"event": "transaction.reversed",
"data": {
"original_transaction_id": "tx_4qYzA1bCdE",
"reversal_transaction_id": "tx_2hJkL3mNpQ",
"reference": "order_789",
"amount_kobo": 500000,
"reason": "Bank-initiated reversal: suspected fraud"
},
"created_at": "2025-06-02T09:15:00Z"
}

Key fields: original_transaction_id, reversal_transaction_id, reason.

Recommended action: This is rare and requires manual review. Look up your order by matching original_transaction_id against the id you stored from the original transaction.completed event. Flag the order for manual review, do not assume the original delivery/service can simply be undone automatically. Notify your operations or support team.


kyc.verified

Fires when a BVN or NIN verification check succeeds.

Triggered by: BVN Verification, NIN Verification.

{
"event": "kyc.verified",
"data": {
"kyc_id": "kyc_8dEfG9hIjK",
"user_ref": "user_123",
"type": "bvn",
"verified_at": "2025-06-01T14:00:08Z"
},
"created_at": "2025-06-01T14:00:09Z"
}

Key fields: user_ref, kyc_id, type (bvn or nin), verified_at.

Recommended action: Update the verification status on your user's record (user_ref), keyed by type if you support multiple verification methods. Unlock any features or transaction limits that were gated behind verification, for example, raising their wallet transaction cap above the Tier 1 unverified threshold.


kyc.failed

Fires when a BVN or NIN verification check fails.

Triggered by: BVN Verification, NIN Verification.

{
"event": "kyc.failed",
"data": {
"kyc_id": "kyc_8dEfG9hIjK",
"user_ref": "user_123",
"type": "bvn",
"failure_reason": "BVN_DOB_MISMATCH"
},
"created_at": "2025-06-01T14:00:09Z"
}

Key fields: user_ref, kyc_id, failure_reason.

Recommended action: Notify the user with a specific, actionable message based on failure_reason, for example, BVN_DOB_MISMATCH should prompt "double check the date of birth you entered," not a generic "verification failed." Do not silently retry; most failure reasons require the user to correct their input. See the KYC Verification guide for the full list of failure codes.


settlement.completed

Fires when a scheduled settlement run pays out your accumulated wallet balance to your registered bank account.

Triggered by: Scheduled settlement runs (T+1 by default; see Dashboard: Settlements).

{
"event": "settlement.completed",
"data": {
"settlement_id": "stl_3kLmN4oPqR",
"amount_kobo": 12500000,
"currency": "NGN",
"period_start": "2025-06-01T00:00:00Z",
"period_end": "2025-06-01T23:59:59Z",
"bank_account": {
"bank_name": "Zenith Bank",
"account_number": "1234567890"
},
"psp_reference": "ZEN-STL-88213400"
},
"created_at": "2025-06-02T06:00:00Z"
}

Key fields: settlement_id, amount_kobo, period_start, period_end, bank_account, psp_reference.

Recommended action: Record the settlement in your own accounting/reconciliation system, matched against the transactions that occurred within period_startperiod_end. Use psp_reference when reconciling against your bank statement, it's the reference the bank will show for the inbound credit.


wallet.frozen

Fires when a wallet's status changes to frozen, either via your own API call or a compliance action initiated by PayKore.

Triggered by: POST /v1/wallets/{id}/freeze, or automated compliance holds.

{
"event": "wallet.frozen",
"data": {
"wallet_id": "wlt_9f3kA2mXpQ",
"user_ref": "user_123",
"reason": "Compliance hold: unusual transaction pattern",
"frozen_at": "2025-06-02T08:30:00Z"
},
"created_at": "2025-06-02T08:30:01Z"
}

Key fields: wallet_id, user_ref, reason, frozen_at.

Recommended action: Immediately disable outbound payment actions in your app's UI for this user_ref, outbound transfers will fail at the API level regardless, but a clear UI state prevents confusing error messages. If reason indicates a compliance hold rather than your own API call, surface a support contact path to the user rather than a generic error.


Next steps