What P2P is
People depositing pay the customers who are withdrawing. One transfer closes both records.
Before
Everything ran through the central account
The depositor paid into the central account, which then paid the withdrawer in a second hop. The central account had to hold a float at all times, and every baht paid out was the merchant’s own money.
With P2P
The depositor pays the withdrawer directly
The platform matches someone depositing with someone withdrawing the same amount and lets them transfer between themselves. The central account only steps in when the match falls short.
How the money travels
The top route is the old one, the bottom route is P2P
Before — two hops through the central account
The central account has to keep a float sitting there
With P2P — direct, one hop
This one transfer closes the deposit and the withdrawal together
When the two sides meet
Same row, same moment. Read across and you can see who is waiting on what.
Deposit side
Another system opens a deposit session for the depositor
Withdrawal side
The merchant creates a withdrawal; the amount is reserved
Deposit side
The platform matches them; the depositor sees the customer account and a QR
Withdrawal side
One leg opens for this depositor
Deposit side
Must transfer within 10 minutes from the registered account, then attach the slip
Withdrawal side
Waiting. Nothing has happened yet
Deposit side
The slip clears and the deposit order is credited
PAYMENT_PAIDWithdrawal side
This leg counts as funded
WITHDRAWAL_PARTIALLY_FUNDEDDeposit side
Done, as far as this depositor is concerned
Withdrawal side
Short of the amount, a new leg opens for the next person; once it is covered, the withdrawal closes
WITHDRAWAL_COMPLETEDOne withdrawal, filled by several people
Legs open as people actually arrive rather than being split up front, so one withdrawal can end with a single depositor or with several.
When the match falls short
Each side has its own way out, and neither is spelled out in the payload.
Deposit side
Falls back to the bank channel
With nobody to match, the platform switches to the bank channel within the same request and the same order. You still get one PAYMENT_PAID; deposit_type tells you which route it took.
Withdrawal side
The central account covers the gap
After 30 minutes unconfirmed with the amount still short, the central account transfers only the remainder through the bank. The withdrawal still ends as WITHDRAWAL_COMPLETED; summary.channel reads HYBRID.
When the depositor says they paid but the system has not seen it
That leg goes into dispute, and everything stays silent until someone decides it.
- 1
The depositor reports a problem
The leg is locked, stops counting down to expiry, and no webhook announces that a dispute was opened.
- 2
A platform admin has to decide it
The merchant cannot decide it, the platform does not resolve it automatically, and no SLA guarantees when it lands.
- 3
The decision cannot be reversed
Decided for the depositor, the deposit side gets PAYMENT_PAID while the withdrawal side stays silent until the record closes.
A leg closed by dispute resolution does not send WITHDRAWAL_PARTIALLY_FUNDED, unlike a leg that settles normally and announces every time. Totalling funded amounts from that event alone leaves one leg out.
What the merchant has to fund
THB_P2P credit is a pre-funded balance. Two things are debited from it.
The fee on every transaction
The payment is credited in full; the fee comes out of the credit separately.
What the central account transfers instead
Much larger than the fee, and absent from the webhook payload — reconcile it from balance history.
Running out of credit means you cannot create new transactions. The arithmetic is on THB_P2P credit
Webhooks P2P produces
One endpoint receives both sides; tell them apart by the event inside.
| event | side | means |
|---|---|---|
PAYMENT_PAID | Deposit side | A leg cleared, or an admin decided a dispute for the depositor. Post the deposit side here. |
PAYMENT_FAILED | Deposit side | A duplicate slip — the only case that produces this event. |
WITHDRAWAL_PARTIALLY_FUNDED | Withdrawal side | Progress report for a settled leg. Never post to your ledger from this. |
WITHDRAWAL_COMPLETED | Withdrawal side | Terminal. The customer received the full amount, from depositors alone or with the central account covering the gap. |
WITHDRAWAL_COMPLETED_PARTIALLY | Withdrawal side | Terminal. The customer received part of it; the rest is refunded to the merchant. |
WITHDRAWAL_REJECT | Withdrawal side | Terminal. Nothing was paid out and the full amount is refunded. |
Read next
THB_P2P credit
The pre-funded balance fees and central-account transfers come out of
Deposit side
The transfer window, the registered account, single-use QR, disputes, and the APIs involved
Withdrawal side
The withdrawal timeline, the central account, and the PromptPay-only API
Checklist
What to verify before going live
