Web3 Direct Payment Webhook
Customer pays a payment link by connecting a Web3 wallet in the checkout UI. Funds are transferred directly to the merchant's master address rather than to a per-link order address.Read webhook-overview.md first for signature verification, retry policy, and the state machine common to all events.
When it fires#
PIK detects an incoming on-chain transfer to a master address, AND the transaction hash matches a pre-recorded payment_transaction row created when the customer initiated checkout. The pre-recorded row is what distinguishes this from a MASTER_RECHARGE.| Trigger condition | Notes |
|---|
toAddress ∈ PIK master addresses | Not an order pool address |
fromAddress ∉ PIK order pool | External payer wallet |
txHash matches an open payment-link transaction | This is what classifies the event as a payment vs. a raw recharge |
Event identifiers#
| Field | Value |
|---|
eventType | WEB3_DIRECT_PAYMENT |
businessRefType | PAYMENT |
direction | IN |
State machine#
PENDING ──── on-chain confirmed ────► CONFIRMED (balance credited)
│
└──────── reverted ─────────────► FAILED
| Status | When | Side effects |
|---|
PENDING | First on-chain detection of the inbound transfer | Payment link order matched; merchant + customer notified by email |
CONFIRMED | Sufficient confirmations reached | Funds become available in the master balance immediately (no separate collect step required) |
FAILED | Transaction reverted or invalidated | No balance change; order should be marked unpaid |
Payload examples#
status = PENDING#
Funds detected on-chain. The system has already cross-referenced the txHash with an open payment link order.{
"event": "transaction.created",
"timestamp": 1738800000000,
"data": {
"fundEventCode": "FE20260206120000002",
"paymentLinkName": "Annual License",
"businessRefType": "PAYMENT",
"chain": "Ethereum",
"tokenSymbol": "USDT",
"tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"txHash": "0x9988776655443322110099887766554433221100998877665544332211009988",
"fromAddress": "0xC0ffee1234567890C0ffee1234567890C0ffee12",
"toAddress": "0xMasterAddressAAAAMasterAddressAAAAMasterAA",
"amount": 1200.00,
"direction": "IN",
"eventType": "WEB3_DIRECT_PAYMENT",
"status": "PENDING",
"createTimeUtc": "2026-02-06 12:00:00"
}
}
status = CONFIRMED#
Same fundEventCode. Funds are now part of the merchant's available master balance.{
"event": "transaction.created",
"timestamp": 1738800180000,
"data": {
"fundEventCode": "FE20260206120000002",
"paymentLinkName": "Annual License",
"businessRefType": "PAYMENT",
"chain": "Ethereum",
"tokenSymbol": "USDT",
"tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"txHash": "0x9988776655443322110099887766554433221100998877665544332211009988",
"fromAddress": "0xC0ffee1234567890C0ffee1234567890C0ffee12",
"toAddress": "0xMasterAddressAAAAMasterAddressAAAAMasterAA",
"amount": 1200.00,
"direction": "IN",
"eventType": "WEB3_DIRECT_PAYMENT",
"status": "CONFIRMED",
"createTimeUtc": "2026-02-06 12:00:00"
}
}
status = FAILED#
{
"event": "transaction.created",
"timestamp": 1738800240000,
"data": {
"fundEventCode": "FE20260206120000002",
"paymentLinkName": "Annual License",
"businessRefType": "PAYMENT",
"chain": "Ethereum",
"tokenSymbol": "USDT",
"tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"txHash": "0x9988776655443322110099887766554433221100998877665544332211009988",
"fromAddress": "0xC0ffee1234567890C0ffee1234567890C0ffee12",
"toAddress": "0xMasterAddressAAAAMasterAddressAAAAMasterAA",
"amount": 1200.00,
"direction": "IN",
"eventType": "WEB3_DIRECT_PAYMENT",
"status": "FAILED",
"createTimeUtc": "2026-02-06 12:00:00"
}
}
Field notes specific to this event#
| Field | Notes |
|---|
paymentLinkName | Always populated — comes from the matched payment link |
toAddress | The merchant master address — same address as used for the rest of master-balance operations |
amount | The amount recorded against the matched payment link, not necessarily the raw on-chain value if there is a discrepancy worth flagging |
How this differs from CUSTOMER_PAYMENT#
| CUSTOMER_PAYMENT | WEB3_DIRECT_PAYMENT |
|---|
| Destination address | Per-link order address | Merchant master address |
Requires a sweep (ORDER_COLLECT_OUT) afterward? | Yes | No — funds land in master immediately |
| Typical customer flow | Manual transfer from any wallet | Web3 wallet connect in checkout |
For Web3 direct payments you will not receive a follow-up ORDER_COLLECT_OUT event.
Recommended handler logic#
1. Verify signature.
2. Look up local order by fundEventCode (idempotency).
3. Switch on status:
PENDING → mark order "Payment Detected" but DO NOT fulfill yet.
CONFIRMED → fulfill order, send receipt.
FAILED → mark order failed.
4. Respond 200 within 5 seconds.
Modified at 2026-05-25 08:36:47