Event Catalog & Payloads
The system sends only these events (the event name matches event_type in the code).
Events that are actually sent
event_type | Sent when |
|---|---|
deposit.success | A deposit was matched and credited to the merchant account (status CREDITED). |
deposit.expired | A deposit timed out / no amount arrived to match within the window (status EXPIRED). |
withdrawal.success | A withdrawal/payout succeeded (status SUCCESS). |
withdrawal.rejected | A withdrawal was rejected (status REJECTED) — has a reason field. |
withdrawal.failed | A withdrawal failed mid-processing (status FAILED) — has a reason field. |
withdrawal.refunded | Money was returned to the merchant balance after a withdrawal was rejected/failed (a refund notification). |
In addition, the "test" button in the Portal sends an event with event_type = webhook.test (minimal payload: {"event_id":"test","event_type":"webhook.test"} plus header X-Webhook-Event-Id: test). It only confirms your endpoint is reachable + returns 2xx — it is not a real event.
withdrawal.refunded returns the gross amount (amount + fee) to your wallet, and it never fires alone on success — it is always paired with a withdrawal.rejected or withdrawal.failed event for the same withdrawal.Payload structure
Every payload is JSON and always carries these shared fields.
| field | type | description |
|---|---|---|
event_id | string | Format <id>:<event_type>, e.g. dep_abc:deposit.success — used for idempotency. |
event_type | string | The event name (per the table above). |
user_ref | string | The merchant-side reference you sent when creating the transaction (invoice/order id), echoed back for reconciliation. |
status | string | The terminal status of the transaction (e.g. CREDITED, EXPIRED, SUCCESS, REJECTED, FAILED). |
livemode | bool | true = a real transaction, false = a sandbox/test transaction. |
| money fields | string|null | Money amounts as baht strings ("100.50"); null if there is no value yet. |
Deposit event (deposit.success, deposit.expired)
| field | type | description |
|---|---|---|
deposit_id | string | Id of the deposit. |
amount | string (baht) | The amount the merchant set for the customer to pay (requested). |
expected_amount | string (baht) | The amount the system expects to actually receive (with cents added for matching). |
matched_amount | string|null | The gross amount that actually arrived — null until CREDITED. |
credited_amount | string|null | The net amount credited to the merchant — null until CREDITED. |
fee | string|null | The fee = matched_amount − credited_amount — null until CREDITED. |
callback_meta | object|null | Metadata the merchant attached when creating the transaction (if any). |
{
"event_id": "dep_abc123:deposit.success",
"event_type": "deposit.success",
"deposit_id": "dep_abc123",
"user_ref": "order-7781",
"amount": "500.00",
"expected_amount": "500.01",
"matched_amount": "500.01",
"credited_amount": "491.01",
"fee": "9.00",
"status": "CREDITED",
"callback_meta": null,
"livemode": true
}
For deposit.expired, the values of matched_amount / credited_amount / fee are null and status = EXPIRED.
Withdrawal event (withdrawal.success, withdrawal.rejected, withdrawal.failed, withdrawal.refunded)
| field | type | description |
|---|---|---|
withdrawal_id | string | Id of the withdrawal. |
amount | string (baht) | The withdrawal amount. |
fee | string (baht) | The withdrawal fee. |
net_payout | string (baht) | The net amount paid out to the destination. |
destination | object | The full payout destination (e.g. {"bank":"KBANK","account_no":"1234567890","name":"Cust"}). |
reason | string | The reason (present only on withdrawal.rejected / withdrawal.failed; absent on success). |
{
"event_id": "wd_xyz789:withdrawal.success",
"event_type": "withdrawal.success",
"withdrawal_id": "wd_xyz789",
"user_ref": "wd-order-7",
"amount": "300.00",
"fee": "5.40",
"net_payout": "294.60",
"destination": { "bank": "KBANK", "account_no": "1234567890", "name": "Cust" },
"status": "SUCCESS",
"livemode": true
}
Example of withdrawal.rejected (with reason):
{
"event_id": "wd_xyz789:withdrawal.rejected",
"event_type": "withdrawal.rejected",
"withdrawal_id": "wd_xyz789",
"user_ref": "wd-order-7",
"amount": "300.00",
"fee": "5.40",
"net_payout": "294.60",
"destination": { "bank": "KBANK", "account_no": "1234567890", "name": "Cust" },
"status": "REJECTED",
"reason": "bank account closed",
"livemode": true
}
kind field (it was removed) — do not depend on this field.::placeholder-note{value="destination in the webhook is the "full plaintext destination" per the system owner's decision — confirm that exposing the full account number in the real payload is intended"} ::
