Payment Requests
Inbox + outbox of payment requests between customers. "I ask you to send me money" — opposite of a transfer.
Transfer vs Request
- Transfer = "I send money to you" (sender pushes)
- Payment request = "I ask you to send money to me" (recipient pulls)
What Customers See
┌──────────────────────────────────────┐
│ H1: Payment requests │
│ Sub: Incoming + outgoing │
├──────────────────────────────────────┤
│ [ Received (3) ] [ Sent (2) ] │
└──────────────────────────────────────┘
URL: /wallet-central/requests/?tab=received (default) or ?tab=sent.
The right-rail card on Wallet Central home shows up to 5 incoming pending requests with inline Approve / Decline buttons:

The admin-side queue lives at Wallet → Fund Requests:

Received Tab
Incoming requests where this customer is the would-be sender.
┌──────────────────────────────────────────────┐
│ Avatar Alice asks for ₹500 │
│ "Lunch split" │
│ [ Approve ] [ Decline ] │
│ [pending pill] │
├──────────────────────────────────────────────┤
│ Avatar Bob asks for ₹100 │
│ "Coffee" │
│ [approved pill] │
└──────────────────────────────────────────────┘
Approve
Click → confirmation dialog with summary:
You'll send ₹500 to Alice.
Note: "Lunch split"
Fee (1%): ₹5
Total debit: ₹505
[ Confirm ] [ Cancel ]
Confirm → standard transfer flow with OTP if amount > threshold. On success row state → approved, both ledger rows written, both parties notified.
Decline
Click → small confirmation. State → declined. Requester gets "Payment request declined" email. Wallet untouched.
Sent Tab
Outgoing requests this customer initiated.
┌──────────────────────────────────────────────┐
│ Avatar Sent ₹500 to Charlie │
│ "Trip share" │
│ Sent 2026-04-22 │
│ [pending pill] [ Cancel ] │
├──────────────────────────────────────────────┤
│ Avatar Sent ₹250 to Diana │
│ "Lunch" │
│ [approved pill] +₹250 received │
└──────────────────────────────────────────────┘
Cancel
Pre-approval — sender can cancel. Click → state cancelled. Recipient notified.
Re-request
After decline / expire, a "Send again" button restarts the flow with same recipient + amount + note.
Request Money (new)
URL /wallet-central/requests/new — form to ask another customer to send.
| Field | Notes |
|---|---|
| From | recipient autocomplete (same lookup as Send) |
| Amount | min/max validated server-side |
| Note | optional |
| Expires in | dropdown — 24h / 3d / 7d / never |
Submit → recipient gets "X requested ₹Y from you" email with link to their inbox.
Pending Count Badge
Sidebar / KPI shows pending count badge:
Payment requests (3 pending)
Empty State
"No incoming requests right now."
[ Request money ]
Setup
Wallet → Settings → Wallet Central → Payment Requests
| Setting | Default | What it does |
|---|---|---|
| Enable | OFF | global toggle |
| Default expiry | 7 days | dropdown default |
| OTP threshold | empty | gate Approve flow with OTP above this amount |
| Max requests per day | empty | rate-limit per requester |
KYC Gate
Optional. Add payment_request to KYC required-features to require approved KYC for creating requests. Approving incoming still goes through the transfer KYC gate.
Common Scenarios
Pre-event split — request from 5 friends
5 separate requests via "Request money". Each friend sees one in their inbox. Each approves independently.
Customer regrets their request
Pre-approval, they cancel from Sent tab.
Auto-expire stale requests
Default 7-day expiry. Cron sweeps daily and marks expired.
When Something Goes Wrong
| Problem | Fix |
|---|---|
| Approve does nothing | Sender lacks balance OR KYC for transfer not approved |
| Pending count not updating | Cache stale — clear via Status Tools |
| Expired requests still pending | Cron not firing — check wp cron event list |
| Recipient never sees the request | Email blocked — check WC mail logs |
For developers — hooks + storage
Hooks
| Hook | Type | When |
|---|---|---|
wkwp_central_request_created | action | new row written |
wkwp_central_request_approved | action | recipient approved → transfer fired |
wkwp_central_request_declined | action | recipient declined |
wkwp_central_request_cancelled | action | requester self-cancelled |
wkwp_central_request_expired_cron | action | nightly expiry sweep |
wkwp_central_request_form_html | filter | rewrite create-form HTML |
Storage
Reuses the wallet payment-requests table with request_type = payment_request (transfers use transfer, QR uses qr_pay).
