Dynamic QR
A fresh QR code per transaction, with the amount embedded. Best for POS terminals, kiosks, and any display that can show a unique QR per sale.
A dynamic QR is a fresh code generated for each transaction, with the amount already embedded. The customer scans it, confirms the amount they're shown, and pays. No typing, no manual amount entry.
This is the right pattern for any setup where you can render a different QR per sale: POS terminals, supermarket checkouts, kiosks, vending machines, digital signage, parking pay-on-foot, restaurant table billing.
When to use a dynamic QR
| ✅ Good fit | ❌ Wrong fit |
|---|---|
| POS terminal with a screen | Static signage that can't change |
| Kiosk or vending machine | Cheap setups with no display (use Static QR) |
| Restaurant bill on a tablet | E-commerce web checkouts (use Bluebox hosted checkout) |
| Customer-facing display showing each sale | High-frequency, low-value scenarios where bulk static is faster |
The flow
For every transaction:
- Create a fresh, use-once code for the exact amount via
POST /code/create. - Display the returned code as a QR on your terminal screen.
- Customer scans and authorises in the Scan to Pay app.
- Scan to Pay sends a webhook to your notification URL.
- Your handler returns HTTP 200 within 45 seconds.
- Display the outcome to the customer at the till.
Steps 1, 5, and 6 are your responsibility; the platform handles the rest.
Create the code
curl -X POST "https://qa.scantopay.io/pluto/code/create" \
-u "$USERNAME:$PASSWORD" \
-H 'Content-Type: application/json' \
-d '{
"merchantReference": "POS-T07-2025-05-14-00037",
"amount": 149.50,
"useOnce": true,
"shortDescription": "Acme Coffee — 1x cappuccino, 1x muffin"
}'Response:
{
"code": "0123456789",
"expiryDate": 1747242000000,
"codeUrl": null
}Key fields for dynamic QR:
| Field | Value | Why |
|---|---|---|
amount | The exact amount in your merchant's currency (typically ZAR) | The customer can't change this — they confirm and pay |
useOnce | true (the default) | Code invalidates after one successful payment, preventing double-charges |
merchantReference | Unique per transaction | Your idempotency key — see Idempotency |
shortDescription | Optional, 5–45 chars | Displayed on the customer's phone — useful for receipts and audit |
expiryDate | Optional — defaults to 30 minutes | Use a shorter expiry for high-traffic terminals to keep the code list clean |
Display the QR
Two options for rendering:
Option A — use the Scan to Pay-rendered PNG. Embed an <img> tag pointing at the QR endpoint and the platform returns a styled QR with optional colour theming:
<img src="https://qa.scantopay.io/pluto/public/stpqr/0123456789" alt="Scan to Pay" />Option B — render the QR yourself. Encode the 10-digit code as a QR using any QR library on your terminal. The payload is just the digits.
See Rendering the QR for the full endpoint reference, colour options, and unstyled variants.
Set the right expiry
The default expiry is 30 minutes from creation. For dynamic QR at a POS, that's longer than you need — most customers complete within 60 seconds, and stale codes lying around make reconciliation harder.
Set expiryDate to a short window (epoch milliseconds):
const expiry = Date.now() + 2 * 60 * 1000; // 2 minutes{
"merchantReference": "POS-T07-...",
"amount": 149.50,
"useOnce": true,
"expiryDate": 1747235520000
}When the code expires unused, the platform automatically transitions it to a terminal state. See QR code lifecycle.
Handle the response at the till
Once the customer authorises, Scan to Pay sends a webhook to your notification URL. Your terminal should:
- Poll your backend for the latest state of
merchantReferenceevery 1–2 seconds while the customer is at the till — or push from your backend via WebSocket. - Display a clear outcome on screen as soon as the state is
SUCCESSor a terminal failure. - Don't release goods until you see
SUCCESS. A code that's been scanned but not yet authorised is not a confirmed payment.
The notification flow is documented on Webhooks.
What's next
- Render the QR with the right styling → Rendering the QR
- Cancel a code if the customer walks away → Managing QR codes
- Understand each code state → QR code lifecycle
- Receive the payment notification → Webhooks
- Refund a completed transaction → Refunds and reversals
Updated 4 days ago
