Transaction Events
Fired whenever a wallet ledger transaction is recorded or changes status. These are the most common events you’ll receive — internal transfers, card charges, staking, rewards, and more all produce them.
| Event | Trigger |
|---|---|
transaction.deposit | A credit transaction was recorded on one of your wallets |
transaction.withdrawal | A debit transaction was recorded on one of your wallets |
reward.payout | A reward credit was paid out |
transaction.status.changed | An existing transaction moved between statuses |
transaction.deposit / transaction.withdrawal / reward.payout
interface TransactionWebhook {
eventType: "transaction.deposit" | "transaction.withdrawal" | "reward.payout";
eventId: string; // UUID, unique per event
timestamp: string; // ISO 8601
transactionId: string;
transactionHash: string;
amount: string;
currency: string; // wallet symbol, e.g. "NGN", "USDT"
type: "credit" | "debit";
status: "successful" | "pending" | "failed" | "reversed";
description: string;
from: string; // source wallet / address / system name
to: string; // destination wallet / address
category: string; // see category table below
metadata: Record<string, unknown>; // category-specific context
}Example — internal transfer withdrawal
{
"eventType": "transaction.withdrawal",
"eventId": "8f2c1a34-6a1b-4a7e-9c2f-3d4e5f6a7b8c",
"timestamp": "2026-03-12T13:42:46.165Z",
"transactionId": "665f1c2e8b6a4a0012a4d920",
"transactionHash": "DR_1700000000000_XXXXXXXX",
"amount": "100",
"currency": "NGN",
"type": "debit",
"status": "successful",
"description": "Internal transfer to 160005",
"from": "625988",
"to": "160005",
"category": "internal_transfer",
"metadata": {
"transferType": "internal",
"recipientWalletId": "665f0aa18b6a4a0012a4d100",
"recipientUserId": "628b228b19ac52002c588525",
"note": "Invoice #42"
}
}Example — reward payout
{
"eventType": "reward.payout",
"eventId": "2b7d9e10-1c2d-4e5f-8a9b-0c1d2e3f4a5b",
"timestamp": "2026-03-13T00:05:00.000Z",
"transactionId": "665f1c2e8b6a4a0012a4d930",
"transactionHash": "RW_1700000000000_XXXXXXXX",
"amount": "1.25",
"currency": "NGN",
"type": "credit",
"status": "successful",
"description": "Daily rewards payout for 1 day(s) - NGN wallet",
"from": "REWARDS_SYSTEM",
"to": "665f0aa18b6a4a0012a4d100",
"category": "reward",
"metadata": {
"rewardType": "daily_interest",
"numberOfDays": 1
}
}Common categories
The category field tells you which product generated the transaction. Common values include:
| Category | Product |
|---|---|
internal_transfer | Wallet-to-wallet transfers |
fiatDeposit / fiatWithdrawal | Bank deposits and withdrawals (these map to bank_transfer.credit / bank_transfer.debit instead) |
card-order, card_payment, card_settlement | Card issuing and card spend |
staking, unstaking, staking_reward | Staking |
borrowing, loan_repayment, liquidation | Borrowing |
reward | Reward payouts (maps to reward.payout) |
checkout_withdrawal | Checkout settlement withdrawals |
correction | Ledger corrections / reversal credits |
uncategorized | Legacy transactions with no category |
Treat category as an open set — new products introduce new categories. Route on eventType and type first, and use category for finer-grained handling.
transaction.status.changed
Fired whenever a transaction’s status transitions (e.g. pending → successful, successful → reversed). One event fires per transition, with a distinct dedupe reference of the form <transactionId>:<previous>-><next>.
interface TransactionStatusChangedWebhook {
eventType: "transaction.status.changed";
eventRef: string; // "<transactionId>:<previousStatus>-><status>"
timestamp: string;
source: string; // internal service that triggered the change
transactionId: string;
transactionHash: string;
linkedTransactionId: string | null; // links debit/credit pairs
correctionForId: string | null; // set when this corrects another transaction
status: string; // new status
previousStatus: string;
type: "credit" | "debit";
category: string;
amount: string;
currency: string;
accountId: string; // wallet ID
subAccountId?: string;
appId: string;
userId: string;
description: string;
failureReason?: string; // set when status becomes "failed"
metadata: Record<string, unknown>;
createdAt: string; // when the transaction was created
updatedAt: string; // when the status changed
}Example
{
"eventType": "transaction.status.changed",
"eventRef": "665f1c2e8b6a4a0012a4d920:pending->successful",
"timestamp": "2026-03-12T13:45:02.101Z",
"source": "banktransfer.service",
"transactionId": "665f1c2e8b6a4a0012a4d920",
"transactionHash": "DR_1700000000000_XXXXXXXX",
"linkedTransactionId": null,
"correctionForId": null,
"status": "successful",
"previousStatus": "pending",
"type": "debit",
"category": "fiatWithdrawal",
"amount": "5000",
"currency": "NGN",
"accountId": "665f0aa18b6a4a0012a4d100",
"appId": "62ee5dbfb029b7002d5b7453",
"userId": "628b228b19ac52002c588525",
"description": "Bank transfer to JOHN DOE",
"metadata": {},
"createdAt": "2026-03-12T13:42:46.165Z",
"updatedAt": "2026-03-12T13:45:02.099Z"
}Handling
async function handleStatusChange(event: TransactionStatusChangedWebhook) {
switch (event.status) {
case "successful":
await markSettled(event.transactionId);
break;
case "failed":
await markFailed(event.transactionId, event.failureReason);
break;
case "reversed":
// A correcting credit exists — see correctionForId on the correction
await handleReversal(event.transactionId);
break;
}
}A transaction.deposit / transaction.withdrawal event tells you a transaction was recorded — its status may still be pending. Wait for transaction.status.changed to successful (or verify server-side) before treating funds as final.