Skip to content
UnknownPay
ไทย
Webhooks

Event Catalog & Payloads

Every webhook event UnknownPay actually sends, plus the shared payload fields and real JSON examples for deposits and withdrawals

The system sends only these events (the event name matches event_type in the code).

Events that are actually sent

event_typeSent when
deposit.successA deposit was matched and credited to the merchant account (status CREDITED).
deposit.expiredA deposit timed out / no amount arrived to match within the window (status EXPIRED).
withdrawal.successA withdrawal/payout succeeded (status SUCCESS).
withdrawal.rejectedA withdrawal was rejected (status REJECTED) — has a reason field.
withdrawal.failedA withdrawal failed mid-processing (status FAILED) — has a reason field.
withdrawal.refundedMoney 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.
You only receive events you have subscribed to — events you did not subscribe to are skipped (no POST, and not counted as a failure).

Payload structure

Every payload is JSON and always carries these shared fields.

fieldtypedescription
event_idstringFormat <id>:<event_type>, e.g. dep_abc:deposit.success — used for idempotency.
event_typestringThe event name (per the table above).
user_refstringThe merchant-side reference you sent when creating the transaction (invoice/order id), echoed back for reconciliation.
statusstringThe terminal status of the transaction (e.g. CREDITED, EXPIRED, SUCCESS, REJECTED, FAILED).
livemodebooltrue = a real transaction, false = a sandbox/test transaction.
money fieldsstring|nullMoney amounts as baht strings ("100.50"); null if there is no value yet.

Deposit event (deposit.success, deposit.expired)

fieldtypedescription
deposit_idstringId of the deposit.
amountstring (baht)The amount the merchant set for the customer to pay (requested).
expected_amountstring (baht)The amount the system expects to actually receive (with cents added for matching).
matched_amountstring|nullThe gross amount that actually arrived — null until CREDITED.
credited_amountstring|nullThe net amount credited to the merchant — null until CREDITED.
feestring|nullThe fee = matched_amount − credited_amountnull until CREDITED.
callback_metaobject|nullMetadata 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)

fieldtypedescription
withdrawal_idstringId of the withdrawal.
amountstring (baht)The withdrawal amount.
feestring (baht)The withdrawal fee.
net_payoutstring (baht)The net amount paid out to the destination.
destinationobjectThe full payout destination (e.g. {"bank":"KBANK","account_no":"1234567890","name":"Cust"}).
reasonstringThe 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
}
The withdrawal payload no longer has a 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"} ::