Skip to main content

Use QR code payments

Create one-time QR payments programmatically with the Payments API. Each payment gets its own short-lived QR code — ideal for dynamic checkouts, kiosks, and invoices generated by your system.

Looking for no-code QR payments?

To create and manage permanent QR codes (reusable, printable, with fixed amounts and callback notifications) from the dashboard, see stores and points of sale. To charge in person from a phone, see the MONEI Pay app.

Permanent vs one-time QR codes

PermanentOne-Time
Created viaDashboard points of salePayments API / MONEI Pay app
URL formathttps://secure.monei.com/codes/{code_id}https://secure.monei.com/payments/{payment_id}/qr
ReusableYes, same QR for multiple transactionsNo, one payment per QR
AmountCustomer enters (manual) or fixedPre-set per payment
ExpirationNever (can be disabled)7 days by default (or custom expireAt via API, any time in the future)
Best forStatic displays, printed materials, tablesDynamic checkout, invoices, mobile POS

This guide covers the one-time flow. For permanent codes, configure a QR-type point of sale — no code required.

Before you begin

Your API key is on MONEI Dashboard → Settings → API Access:

1. Create a payment (server-side)

Create a Payment on your server with an amount and currency.

POST https://api.monei.com/v1/payments
curl --request POST 'https://api.monei.com/v1/payments' \
--header 'Authorization: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"amount": 110,
"currency": "EUR",
"orderId": "14379133960355",
"callbackUrl": "https://example.com/checkout/callback"
}'

(Replace YOUR_API_KEY with your actual MONEI API key)

Required Parameters:

  • amount positive integer: Amount in the (e.g., 110 for €1.10).
  • currency string: Three-letter ISO currency code (e.g., EUR).
  • orderId string: Your unique order identifier.
  • callbackUrl string: Your server endpoint URL for asynchronous webhook notifications.

Optional Parameters:

  • allowedPaymentMethods array: Restrict available payment methods (e.g., ["card", "bizum"])
  • description string: Payment description shown on the payment page
  • customer object: Pre-fill customer info (email, name, phone)
  • metadata object: Custom key-value pairs for tracking/
  • storeId string: Associate payment with a store (for grouping and user access control)
  • pointOfSaleId string: Link payment to a POS (for grouping and user access control)
  • expireAt integer: Unix timestamp for custom expiration (default: 7 days from creation; must be in the future)

Check all available request parameters.

The API response includes the payment.id, which you'll use in the next step.

2. Display the QR code

Use the payment.id from Step 1 to present the QR code to your customer.

QRQR demo

Option 1: Embed QR Image Directly

Construct the QR code image URL: https://secure.monei.com/payments/{payment_id}/qr

You can render it directly on a webpage or display:

<img
src="https://secure.monei.com/payments/{{payment_id}}/qr?format=svg&size=300"
alt="Scan to Pay"
width="300"
height="300"
/>
  • Replace {{payment_id}} with the actual ID.
  • Use ?format=svg for SVG (default is png).
  • Use ?size=400 to specify size (min: 100, max: 1000, default: 300).

Example QR

Option 2: Redirect to Hosted Page with QR

The Payment object returned in Step 1 also contains payment.nextAction.redirectUrl. Append ?qr=1 to this URL to get a link to a MONEI-hosted page displaying the QR code.

Example: https://secure.monei.com/payments/{payment_id}?qr=1

Hosted Payment Page QR

Customer Interaction:

The customer scans the QR code with their phone and completes the payment on the MONEI payment page using their chosen method.

warning

The QR code payment link is valid until the payment expires — 7 days by default, or the custom expireAt you set (any time in the future). After that, you must create a new payment request.

3. Process the webhook notification (server-side)

MONEI sends the final, authoritative payment status via an asynchronous HTTP POST request to the callbackUrl you provided in Step 1. The request body contains the full Payment object in JSON format.

This webhook ensures you get the definitive status even if the customer closes their browser or loses connection after scanning.

Crucially, you must:

  1. Verify the MONEI-Signature header included in the request. This confirms the webhook genuinely came from MONEI. See the Verify Signatures guide for implementation details.
  2. Return a 200 OK HTTP status code immediately upon receiving the webhook to acknowledge receipt. Any other status code tells MONEI the notification failed.

If MONEI doesn't receive a 200 OK, it will retry sending the webhook.

Once the signature is verified, inspect the status field in the Payment object to confirm payment success (SUCCEEDED) and fulfill the order, or handle failures.

Alternative: poll payment status

For kiosk or display scenarios where you need real-time status updates, poll the payment status instead of (or in addition to) webhooks.

GET https://api.monei.com/v1/payments/{payment_id}
curl --request GET 'https://api.monei.com/v1/payments/{payment_id}' \
--header 'Authorization: YOUR_API_KEY'

Status values: PENDING, PENDING_PROCESSING, SUCCEEDED, FAILED, CANCELED, EXPIRED

Polling Best Practice

Poll every 2-3 seconds. Stop when status is no longer PENDING/PENDING_PROCESSING or when the QR expires.

Customization

You can customize the appearance of the QR code (color, icon) and the hosted payment page in your MONEI Dashboard → Settings → Branding. The Icon you upload there is also the icon MONEI puts at the centre of your QR codes, and Primary color is the colour they are drawn in:

Testing

Troubleshooting

QR code expired QR codes are valid until the payment expires (7 days by default). Create a new payment if the code expires.

Payment method not showing Check that the method is enabled in your account and not filtered by allowedPaymentMethods.

Webhook not received Verify your callbackUrl is publicly accessible, returns 200 OK, and check webhook logs in Dashboard.