Payload structure
Every webhook has the same envelope. Transaction details live underdata. The envelope below shows every field that can appear — only the fields applicable to a given transaction are actually present (see the note).
The payload carries only the fields relevant to the transaction — inapplicable fields are omitted entirely, not returned as
null. This applies at every level: a fiat bank payout has no network, exchange_rate, wallet_address or wallet_chain; a crypto payout has no bank fields; a deposit has no beneficiary. So a field’s absence simply means it doesn’t apply. The only exception is metadata, which is passed through exactly as you supplied it. Match transactions by transaction_id (or reference), and treat any missing field as not applicable.Field reference
| Field | Description |
|---|---|
event | Event type — see Events |
event_id | Stable id for the logical event (use to deduplicate) |
created_at | When the event was generated (ISO 8601) |
data.transaction_id | Rolla transaction id |
data.reference | Transaction reference (the external reference) |
data.type | deposit or payout |
data.status | The transaction status this event represents — one of pending, processing, sent, completed, failed, rejected, refunded (matches the event type). See Events |
data.rail | fiat or stablecoin |
data.amount / data.currency | The net amount the counterparty receives (in minor units — see Amount format), and its currency — a deposit’s credited amount, or a payout’s amount to the beneficiary. Equals destination_amount. |
data.source_amount / data.source_currency | The debit leg, in minor units. For a payout this is the gross amount, i.e. amount + fee; for FX it’s the source-currency amount. |
data.destination_amount / data.destination_currency | The credit leg, in minor units — what the beneficiary/wallet actually receives. |
data.exchange_rate | The effective rate for the conversion, computed as destination_amount / source_amount (destination per source, in minor units) — the same convention as the external transactions API. Present only for FX transactions (source and destination currencies differ); omitted otherwise. |
data.fee_amount | Fee applied, in minor units |
data.beneficiary | Beneficiary details — present for payouts, omitted otherwise (see below). Only fields relevant to the payout are included. |
data.network | On-chain details — present only for genuinely on-chain transactions (a real chain and/or wallet address). chain is the full network name (Solana); tx_hash is the on-chain transaction hash. Omitted for transactions with no on-chain leg — including stablecoin-funded payouts that settle to a fiat bank (e.g. a USDT → USD wire). |
data.metadata | Any metadata you supplied when creating the transaction |
Amount format
All monetary fields —amount, source_amount, destination_amount, and fee_amount — are integers equal to the major-currency value × 100 (two implied decimal places). This is the same scale for every currency, fiat and stablecoin alike — to get the human-readable amount, always divide by 100.
| Currency | Minor unit | Major → minor |
|---|---|---|
| NGN | kobo (1/100) | ₦100 → 10000 |
| USD | cents (1/100) | $100 → 10000 |
| XAF | 1/100 | 1,000 XAF → 100000 |
| USDC | 1/100 | 100 USDC → 10000 |
| USDT | 1/100 | 100 USDT → 10000 |
amount / 100) for any currency.
Webhook amounts differ from the REST transaction endpoints. Webhook payloads report amounts as major × 100 (e.g.
1000 = 10.00). So the same transaction shows 1000 in its webhook and 10 over REST. Match a webhook to a REST record by transaction_id (or reference), not by comparing raw amounts, and apply the right scale for each source.The beneficiary object (payouts)
Drawn from this whitelisted set — but only the fields relevant to the payout are returned. Empty/null fields are omitted, so a fiat bank payout returns bank-account fields (no wallet fields), while a crypto payout returns wallet fields (no bank fields). Internal fields (your business_id, row timestamps) are never included.
id · account_name · account_number · bank_name · bank_code · bank_address · currency · withdrawal_method · routing_number · swift_code · iban · bic · sort_code · intermediary_bank_name · intermediary_bank_routing_number · wallet_address · wallet_chain · email · contact_person · label · beneficiary_address
wallet_chain is the full network name (Solana). Inside bank_address / beneficiary_address, country is the full country name (e.g. Côte d'Ivoire, not CI). A present id means the payout went to a saved beneficiary (it’s the beneficiary’s UUID). One-time (inline) beneficiaries have no id field at all — use its absence to detect them.Sample: Fiat deposit completed
Sample: Fiat payout completed
Sample: FX payout (NGN → USD) pending
A cross-currency payout.exchange_rate is populated (the quoted rate for the pair), and the wire beneficiary’s bank_address.country is the full country name. Only the bank-relevant beneficiary fields are present.
Here
exchange_rate is destination_amount / source_amount = 100000 / 160000000 = 0.000625 (USD minor units per NGN minor unit). Use source_amount and destination_amount for exact reconciliation — they are the authoritative debit and credit legs in minor units.Sample: Stablecoin deposit completed
Sample: Stablecoin payout pending (one-time beneficiary)
Account event payloads
Account events (account.onboarded, account.submitted, account.approved, account.virtual_account.created) describe an account rather than a transaction, so data carries the account fields. transaction_id is not present.
| Field | Type | Description |
|---|---|---|
data.account_id | string | The account (business or individual) the event is about. |
data.name | string | Account name. Omitted if not available. |
data.email | string | Account email. Omitted if not available. |
data.entity_type | string | business or individual. Omitted if not available. |
data.status | string | The application status (draft, submitted, approved, …). Omitted if not available. |
data.virtual_account | object | Present on account.virtual_account.created — the provisioned deposit account. Omitted otherwise. |