QR Ph API
How to generate a dynamic QR code and receive webhook confirmation or poll for payment status.
Overview
Dynamic QR Ph codes are generated per transaction through the Payment Intent workflow. Each code is single-use, encodes the exact payment amount, and expires after 30 minutes by default if not scanned. Once the customer scans and pays, the Payment Intent moves to succeeded.
Generate a QR code
Create a Payment Intent
Include "qrph" in payment_method_allowed:
curl -X POST https://api.paymongo.com/v1/payment_intents \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'sk_test_YOUR_SECRET_KEY:' | base64)" \
-d '{
"data": {
"attributes": {
"amount": 10000,
"currency": "PHP",
"payment_method_allowed": ["qrph"],
"description": "Order #1234"
}
}
}'Send the client_key from the response to your frontend.
Create a QR Ph Payment Method
const response = await fetch('https://api.paymongo.com/v1/payment_methods', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa('pk_test_YOUR_PUBLIC_KEY:')
},
body: JSON.stringify({
data: {
attributes: {
type: 'qrph'
}
}
})
});
const paymentMethod = await response.json();Attach the Payment Method
const attachResponse = await fetch(
`https://api.paymongo.com/v1/payment_intents/${paymentIntentId}/attach`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa('pk_test_YOUR_PUBLIC_KEY:')
},
body: JSON.stringify({
data: {
attributes: {
payment_method: paymentMethodId,
client_key: clientKey
}
}
})
}
);
const intent = await attachResponse.json();Display the QR code
After a successful attach, the Payment Intent status is awaiting_next_action. The QR code is in next_action.code.image_url as a Base64-encoded string:
const imageUrl = intent.data.attributes.next_action.code.image_url;
// Render in an <img> tag:
// <img src={imageUrl} alt="Scan to pay" />Display the QR code prominently. The customer scans it using their banking or e-wallet app.
QR code expiry
| Setting | Value |
|---|---|
| Default expiry | 30 minutes |
| Configurable range | 60–9000 seconds |
To customize expiry, set data.attributes.expiry_seconds when creating a payment method.
Updated about 4 hours ago