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.

mode must be p2p. 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_amount is 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
  }'

amount is 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:

  1. Ensure your webhook endpoint is reachable over HTTPS with valid TLS.
  2. Confirm your live wallet is activated and funded.