Move money with Wallet QR
Generate a QR to receive funds into your wallet, or scan one to push funds out — in four steps.
This guide walks you through both directions of a Wallet QR flow using the API. Authentication and API key setup follow the same pattern as Move money with API — if you've done that guide, steps 1 and 2 will be familiar.
Prerequisites
- A PayMongo merchant account with at least one wallet activated.
- Your live secret API key from the Dashboard (
sk_live_...). Wallet QR does not support test mode — all requests must use a live key. - A registered webhook endpoint listening for
qr.paid— see Webhooks.
1. Authenticate
Every request uses HTTP Basic Auth: your live secret key as the username, with an empty password.
curl https://api.paymongo.com/v2/wallets \
-u sk_live_xxxxxxxxxxxxxxxxxxxxxxxx:If the call returns 401 Unauthorized, check that you're using a live secret key (starts with sk_live_) and that the trailing colon is present.
2. Generate a QR to receive money
Generate a QR code and share it with whoever needs to send funds into your wallet. They scan it with any QR Ph-compatible app — GCash, Maya, or any Philippine bank — and the funds arrive in real time over InstaPay.
modemust bep2p. This routes the QR through the wallet money-movement flow. Other modes (p2b,p2m,p2micro) are part of the QR Ph payment acceptance flow and behave differently — see QR Ph under Payment Acceptance.
For the full parameter reference, see Generate an MPM QR.
Static QR — the sender supplies the amount at scan time. Use this for a reusable top-up QR:
curl --request POST \
--url https://api.paymongo.com/v3/qr/mpm/generate \
--header 'Authorization: Basic <base64-encoded-secret-key>' \
--header 'Content-Type: application/json' \
--data '{
"nation": "ph",
"mode": "p2p",
"type": "static",
"transaction_currency": "PHP"
}'Dynamic QR — the amount is fixed at generation time. Use this when you need to request a specific amount. Set expiry_seconds to control how long the QR stays valid (60–9,000 seconds; default 1,800):
curl --request POST \
--url https://api.paymongo.com/v3/qr/mpm/generate \
--header 'Authorization: Basic <base64-encoded-secret-key>' \
--header 'Content-Type: application/json' \
--data '{
"nation": "ph",
"mode": "p2p",
"type": "dynamic",
"transaction_currency": "PHP",
"transaction_amount": 50000,
"expiry_seconds": 600
}'
transaction_amountis in centavos. ₱500.00 =50000.
Response
{
"qr_string": "00020101021127580012com.p2pqrpay...",
"qr_image": null
}Take note of qr_string — you'll need it to render the QR and, if you're implementing the send direction, to execute a transfer against it. Set qr_image: true in the request if you want a base64-encoded PNG you can display directly.
3. Display the QR and confirm receipt
Render the qr_string using any standard QR library in your application, or display the qr_image PNG directly.
Once the sender scans and pays, PayMongo delivers a qr.paid event to your registered webhook endpoint. Listen for it to confirm the payment landed:
{
"data": {
"type": "qr.paid",
...
}
}For the full event payload structure, see Payload structure.
When qr.paid fires, the corresponding inward transfer is already recorded on your wallet ledger. No polling needed — update your system state on receipt of the event.
4. Scan a QR to send money
To push funds out of your wallet, decode a recipient's QR code to get the qr_string, then execute a transfer against it.
For the full parameter reference, see Execute Transfer QR.
curl --request POST \
--url https://api.paymongo.com/v2/qr/transfer \
--header 'Authorization: Basic <base64-encoded-secret-key>' \
--header 'Content-Type: application/json' \
--data '{
"transaction_reference_number": "TXN-20240625-001",
"qr_string": "00020101021127580012com.p2pqrpay...",
"amount": 500.00
}'
amountis in pesos (not centavos) and is required only when the scanned QR is static — dynamic QRs already encode the amount.
The recipient's wallet is credited in real time. Your wallet is debited and the movement is recorded on your ledger.
Some QR strings include *** placeholder values in their Additional Data Fields, signaling that the scanner should supply those values. See Wallet QR — Optional parameters for the full list of overridable fields.
Going live
Wallet QR requires a live key from the start — there is no test mode. Before going live:
- Ensure your webhook endpoint is reachable over HTTPS with valid TLS.
- Confirm your live wallet is activated and funded.