Wallet QR
Use a QR code to receive money into your PayMongo Wallet or send money out — no account number required.
How Wallet QR works
Wallet QR lets you move money to and from your PayMongo Wallet using QR Ph-standard codes. There are two directions:
- Receive — generate a QR code that anyone with a QR Ph-compatible app (GCash, Maya, any Philippine bank) can scan to send money directly into your Wallet.
- Send — scan a recipient's QR code via the API to push money out of your Wallet into theirs.
Both flows run on the QR Ph standard, which means they settle in real time over InstaPay.
Not the same as Payment Acceptance QR Ph. Payment Acceptance QR Ph is for accepting customer payments against a payment intent — it's a checkout flow. Wallet QR is a money-movement tool: it moves funds into or out of your Wallet balance, the same way a bank transfer would. If you're building a checkout, see QR Ph under Payment Acceptance instead.
QR types
Every QR you generate is either static or dynamic.
| Type | Amount | Expiry | Best for |
|---|---|---|---|
| Static | Supplied by the scanner at the time of payment | None — valid indefinitely | Shareable QRs, top-up flows, recurring senders |
| Dynamic | Encoded in the QR at generation time | Yes — 60 to 9,000 seconds (default: 1,800) | One-time requests for a specific amount |
Static QRs are convenient for display (a printed QR, a UI element your users scan repeatedly). Dynamic QRs give you precise control over the transaction amount and automatically expire after a set window.
Receiving money: generate a QR
To receive money into your Wallet, generate a QR code and share it. The sender scans it with any QR Ph-compatible app and sends funds directly to your Wallet.
For the full API reference, see Generate an MPM QR.
Required parameters
| Parameter | Type | Value |
|---|---|---|
nation | string | ph |
mode | string | p2p |
type | string | static or dynamic |
transaction_currency | string | PHP |
Optional parameters
| Parameter | Type | Notes |
|---|---|---|
transaction_amount | integer | Required for dynamic QRs. In centavos — ₱100.00 = 10000. Must not be set for static QRs. |
expiry_seconds | integer | Dynamic QRs only. Seconds until expiry, between 60 and 9,000. Defaults to 1,800 (30 minutes). |
qr_image | boolean | Set to true to receive a base64-encoded PNG of the QR alongside the QR string. Defaults to false. |
Examples
Static QR — sender supplies the amount on scan:
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 — amount fixed at ₱500.00, expires in 10 minutes:
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,
"qr_image": true
}'Response
The response includes a qr_string — the raw QR Ph-standard string — and, if qr_image was true, a base64-encoded PNG you can render directly in your UI.
Use the qr_string to render the QR yourself (any standard QR library works), or display the qr_image directly.
Sending money: scan a QR
To send money out of your Wallet, supply the QR string from a scanned QR code. Your Wallet is debited and the encoded recipient's account is credited in real time.
For the full API reference, see Execute Transfer QR.
Required parameters
| Parameter | Type | Notes |
|---|---|---|
transaction_reference_number | string | A unique identifier you generate for this transaction. |
qr_string | string | The raw QR string decoded from the scanned QR code. |
amount | float | Required if the scanned QR is static (no amount was encoded). In pesos — e.g. 100.50. Not required for dynamic QRs. |
Optional parameters
Some QR strings contain placeholder values (***) in their Additional Data Fields. These indicate that the QR generator is requesting the scanner to supply those values. Only fields marked with *** in the original QR can be supplied — any field you pass for a tag that was not present in the original QR will be ignored.
| Field | Tag | Notes |
|---|---|---|
bill_number | 62/01 | Arbitrary string, 1–35 characters. |
mobile_number | 62/02 | Must match +[country code]-[number] format. |
store_label | 62/03 | Arbitrary string, 1–35 characters. |
loyalty_number | 62/04 | Arbitrary string, 1–35 characters. |
reference_label | 62/05 | Arbitrary string, 1–35 characters. |
customer_label | 62/06 | Arbitrary string, 1–35 characters. |
terminal_label | 62/07 | Arbitrary string, 1–35 characters. |
purpose_of_transaction | 62/08 | Arbitrary string, 1–35 characters. |
Example
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,
"purpose_of_transaction": "Supplier payment"
}'QR lifecycle
Static QRs
Static QRs do not expire. The same code can be scanned and paid multiple times. Each successful scan creates a new inward transfer and a corresponding ledger entry on your Wallet.
Dynamic QRs
Dynamic QRs have a defined expiry window set at generation time (expiry_seconds). Once expired, the QR cannot be paid — the scanner's app will reject it. Generate a new dynamic QR for each transaction where you need to control the amount.
| State | Meaning |
|---|---|
| Active | Within the expiry window — can be scanned and paid |
| Expired | Past the expiry window — payment will be rejected |
| Paid | Successfully paid — the corresponding transfer is recorded on your ledger |
Webhooks
Register a webhook endpoint via the Webhooks API to receive real-time notifications on QR activity.
| Event | Trigger |
|---|---|
qr.paid | A QR code was successfully paid. Fires for both static and dynamic QRs. |
qr.expired | A QR code has expired. For dynamic QRs, fires when the expiry_seconds window elapses. For static QRs, fires only when the QR is explicitly expired via the expire endpoint. |
For the payload structure shared across webhook events, see Payload structure.
Limits
QR Ph transfers count against your Wallet's daily outward limit (when sending) and daily inward limit (when receiving). For the QR Ph-specific limits on consumer wallets, see the limits table on the Wallets page.
Per-transaction limits follow the QR Ph network standard. Contact [email protected] for your account's specific limits.
Note: Hitting a wallet limit fails the transfer at submission. Check your Wallet's running totals before issuing high-volume scans.
Related reading
- Wallets — wallet types, statuses, and limits.
- Manage your balance — other ways to top up your Wallet.
- Send money — bank and e-wallet transfers via InstaPay and PESONet.
- Key concepts — how transfers, rails, and the ledger work.
- QR Ph (Payment Acceptance) — accepting customer payments via QR (different from Wallet QR).