QR Code Payments in Europe — Initiation, Tracking, and Getting Notified
The ideal payment experience for a merchant: the customer scans a QR code, does something in their banking app, and the till beeps green. No card machine, no card fees, no card network. Just a bank transfer. The money is in your account in seconds.
This is technically achievable in the EU today — but the path there is more nuanced than it first appears. There are three meaningfully different approaches, each with different trade-offs around friction, tracking reliability, and infrastructure complexity. This post maps all of them.
The Fundamental Problem
EPC QR codes (covered here) solve one half of the problem beautifully: they pre-fill the banking app with the recipient's IBAN, name, amount, and payment reference. The user taps confirm. Done.
What they don't solve is the other half: how does the merchant know the payment happened?
Once the user presses confirm in their banking app, the bank executes a standard SEPA Credit Transfer. No webhook fires to your server. No API call goes out. The bank has no idea who generated the QR code or why — it just sees a credit transfer with a reference string. The EPC standard has no notification mechanism.
So you're left with:
- Trust — display "thank you" and hope they paid (bad for anything above a donation jar)
- Poll your own account — check for incoming transactions periodically via AISP
- Use a PISP — initiate the payment yourself, get notified when the bank executes it
Approach 1: EPC QR + Polling Your Own Account
How it works:
- Generate an EPC QR code with a unique payment reference per transaction (ISO 11649 structured creditor reference — more on this below)
- Display it to the customer
- Customer scans it, their banking app opens pre-filled, they confirm
- Your server polls your own bank account via an AISP API, looking for an incoming transaction matching the reference
EPC QR (pre-filled IBAN + amount + unique ref)
↓ customer scans + confirms
↓ SEPA Credit Transfer executes
↓ your server polls GoCardless API every N minutes
↓ transaction appears with matching reference
↓ payment confirmed, order fulfilled
Why this can work well:
- Zero friction for the customer — their banking app, their normal confirm flow, no redirect to a third-party site
- No extra auth step beyond what they'd normally do in their app
- Works with any bank that supports EPC QR scanning (most EU banking apps do)
- With SEPA Instant (SCT Inst), the transfer settles in under 10 seconds at the bank level
The polling rate limit problem:
Under PSD2's RTS (Article 36), banks must allow at minimum 4 AIS (Account Information Service) requests per day per account without requiring additional customer authentication. This is the regulatory floor — some banks allow more on dedicated interfaces.
What this means in practice: if you're polling your merchant account via GoCardless four times a day, you'd detect a payment within a 6-hour window at worst. That's fine for invoices and asynchronous payments, completely wrong for point-of-sale.
Getting around the rate limit:
Several strategies help:
- Use a provider that caches and pushes. GoCardless and similar providers maintain their own connection to banks and can use webhook or notification mechanisms where available. You poll the provider's cache, not the raw bank API.
- Use a neobank with real-time push. Revolut Business, N26 Business, and Bunq expose webhook notifications for incoming transactions via their own APIs — separate from the standard PSD2 AISP interface. These aren't subject to the 4x/day rule because you're talking directly to your own account's API, not acting as a third-party AISP.
- The bank's own notification infrastructure. Wise Business, Stripe Treasury, and others offer push notification on incoming payments. If your merchant account is at one of these providers, you can receive a webhook within seconds of an SCT Inst settling.
The reference matching piece:
For this approach to work, the payment reference must be unique and reliably transmitted. Use a structured creditor reference (ISO 11649) — a standardised format that surviving transit through most European banking systems:
RF + 2-digit checksum + up to 21 alphanumeric characters
Example: RF93 ORDER 42 2026 0225 — but in practice, most libraries generate this for you from an arbitrary identifier.
Put the structured reference on line 10 of the EPC payload (not line 11 — see the EPC QR post for the format). Banks preserve it with higher fidelity than free-text remittance info.
BCD
002
1
SCT
Acme Merchant GmbH
DE89370400440532013000
EUR24.99
RF93ORD420260225
↑ structured creditor reference
When the transfer lands in your account, your AISP response will include this reference in remittanceInformationStructured, letting you match it to the pending order.
Approach 2: PISP with QR Code Redirect
How it works:
Instead of an EPC QR code (which encodes IBAN + amount directly), the QR code contains a URL pointing to your server. The user scans it and is taken through a PISP-initiated payment flow:
QR code → https://yourapp.com/pay/order-id-42
↓ user scans on phone
↓ mobile browser opens
↓ your server creates payment initiation via Tink/Salt Edge/etc.
↓ user redirected to their bank's authorisation page
↓ user authenticates with SCA (Face ID / fingerprint / OTP)
↓ bank executes SCT or SCT Inst
↓ PISP provider sends webhook to your server
↓ merchant notified within seconds
The SCA step:
This is the unavoidable friction in the PISP approach. PSD2 mandates SCA on every payment initiation — the user must authenticate with their bank directly before any money moves. Banks cannot delegate this to the PISP.
What SCA looks like from the user's perspective:
- Redirected to their bank's app or mobile web interface
- Prompted for biometric (Face ID / fingerprint) or OTP
- Payment shown for confirmation
- Redirect back to your site
For most users in countries where mobile banking is mature (Germany, Netherlands, Nordics), this is a ~10-15 second process via app-to-app redirect. Still more friction than confirming a pre-filled EPC payment, but not dramatically so.
Why PISP is worth it:
- Webhook notification — you get called back by the PISP provider within seconds of the payment being submitted to the bank
- Payment status tracking — the PISP payment has a transaction ID you can query
- Guaranteed reference — you control the payment metadata, no risk of the user changing the reference
- Can handle edge cases — failed authorisations, insufficient funds, bank timeouts — all surfaced via status codes
The webhook payload (Tink-style):
{
"event": "payment.status.changed",
"paymentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "SETTLED",
"amount": { "value": 24.99, "currency": "EUR" },
"reference": "ORDER-42",
"creditorIban": "DE89370400440532013000",
"settledAt": "2026-02-25T14:31:02Z"
}
SETTLED means the bank has confirmed execution. For SCT Inst, this arrives in under 10 seconds from authorisation.
Approach 3: Hybrid — EPC QR + Merchant-Side Neobank Webhook
A middle ground that avoids both the polling frequency problem and the SCA redirect:
- Use an EPC QR code for zero-friction customer UX
- Open your merchant account at a provider with real-time incoming payment webhooks (Revolut Business, Wise Business, Bunq, Stripe)
- Configure the webhook to notify your server on every incoming credit
Customer scans EPC QR → confirms in their banking app
↓
SCT Inst lands in your Revolut Business account (< 10s)
↓
Revolut fires webhook to your server
↓
Your server matches reference → marks order paid
↓
Merchant UI updates
Why this works:
- Customer experience: scan, pre-filled payment, confirm. No redirect. Same as approach 1.
- Merchant experience: webhook arrives seconds after the SCT Inst settles. Same as approach 2.
- No PISP licence needed. No redirect flow. Just a Revolut Business account with webhooks enabled.
Why it doesn't always work:
- SCT Inst is now mandatory for outgoing transfers from October 2025 (EU Instant Payments Regulation), but not all banks route payments as instant by default — the user's bank may send regular SCT, which settles next business day.
- Revolut Business webhooks are a proprietary API — you're not using PSD2 at all on the merchant side, just Revolut's platform product. If Revolut changes their API or you switch banks, you rebuild the integration.
- Reference preservation — some banks mangle or truncate the reference during SCT transit, making matching less reliable. Structured references (ISO 11649) help here.
SEPA Instant — The Game Changer
SCT Inst (SEPA Instant Credit Transfer) is what makes any of these approaches viable for point-of-sale:
- Maximum settlement time: 10 seconds (20s in exceptional circumstances)
- Available 24/7/365 — not just business days
- Mandatory from January 2025 (incoming) / October 2025 (outgoing) under EU Regulation 2024/886
- Maximum transaction amount: €100,000 (raised from the original €15,000 cap in 2019)
- The bank scheme verifies the payee name against the IBAN (Verification of Payee, required from October 2025)
Before the mandatory instant payments regulation, only ~60% of EU banks offered SCT Inst at all. The mandate changes this: by end of 2025, every EU bank must send and receive instant payments. This is the foundation that makes near-real-time reconciliation realistic.
Provider Comparison for PISP Flows
If you go the PISP route (approach 2), here's how the main providers compare for payment initiation:
| Provider | Webhook notification | Countries | SCA model | Notes |
|---|---|---|---|---|
| Tink (Visa) | ✅ Real-time | 18 EU countries | App-to-app / redirect | Most enterprise-grade; requires commercial contract |
| TrueLayer | ✅ Real-time | UK + key EU markets | App-to-app (biometric) | "Pay by Bank" product; 40% of UK Pay by Bank volume; 20M consumer network; merchant account included; WooCommerce/Shopify plugins; hosted & embedded checkout options |
| Yapily | ✅ Webhooks | 19 countries (UK + EU, strong in UK & Germany) | App-to-app / redirect | Developer-API focused; both AISP + PISP from one integration; Variable Recurring Payments supported; used by Pleo, Crezco |
| Salt Edge | ✅ Callbacks | 50+ countries | Redirect | Good EU coverage; Partner Programme |
| Token.io | ✅ Webhooks | 18 EU countries | App-to-app / redirect | Payment-initiation focused; clean API |
| Banked | ✅ Webhooks | UK + limited EU | Redirect | UK-strong; EU coverage growing |
| GoCardless | ❌ AISP only | 31 countries | N/A | No PISP — read-only |
| Plaid | ❌ AISP only (EU) | 6 EU markets | N/A | Payment initiation EU not offered |
For a European merchant wanting QR-initiated payments with webhook notification, Tink or Token.io are the strongest choices. Token.io is notably focused on the payment initiation use case specifically.
Putting It Together: A Practical Point-of-Sale Architecture
Here's a concrete design for a small merchant wanting QR-to-notification payments:
Option A (low friction, slightly slower): EPC QR + Neobank webhook
Order created
↓
Generate unique ISO 11649 reference for this order
Generate EPC QR: IBAN + amount + reference
Display QR on POS screen / print on invoice
↓
Customer scans with banking app → confirms
SCT Inst settles in < 10s
↓
Revolut/Wise/Bunq webhook fires to your server
Match reference → mark paid
POS updates
Infrastructure: your server + webhook receiver + Revolut Business API. No PISP licence. Cost: ~0 (Revolut Business account is free for basic use).
Option B (full tracking): PISP redirect QR
Order created → your server generates a payment session
QR code → https://pay.yourapp.com/session/{id}
↓
Customer scans on phone
Mobile browser → your server redirects to PISP provider (e.g. Token.io)
PISP redirects to customer's bank for SCA
Customer authenticates, confirms payment
Bank executes SCT Inst
PISP webhook → your server
Order marked paid → POS updates
Infrastructure: server + PISP API integration + webhook receiver. Requires commercial agreement with PISP provider. Cost: per-transaction fee (typically 0.1–0.3% or fixed pence/cents per transaction — considerably cheaper than card).
Option C (simplest, async): EPC QR + AISP polling (for invoices)
For invoices and non-instant use cases (online orders, B2B):
Invoice sent with EPC QR embedded
Customer pays whenever
AISP polls your account 4x/day
Reference matched → invoice marked paid
Customer and you both notified
No real-time notification, but for payment terms of net-7 or net-30, this is completely fine and the simplest possible implementation.
A Note on Verification of Payee
From October 2025, all EU instant payments require VoP — the sending bank must verify that the beneficiary name in the payment matches the IBAN owner before proceeding. The EPC and PISP flows both go through this check.
What this means:
- Your merchant IBAN must match your registered business name exactly (or close enough — banks are implementing fuzzy matching)
- If a customer edits the beneficiary name in the EPC QR pre-fill (which banking apps technically allow), VoP may warn them of a mismatch
- For PISP flows, VoP happens automatically at the bank before the user confirms — no extra UI step for the user, just a possible warning if something doesn't match
Summary: Which Approach for Which Use Case?
| Use case | Recommended approach | Why |
|---|---|---|
| Physical POS (café, market stall) | Option A — EPC QR + neobank webhook | Low friction, fast with SCT Inst |
| Online checkout | Option B — PISP redirect QR | Full tracking, redirect acceptable on desktop |
| Invoicing / B2B | Option C — EPC QR + AISP polling | Async is fine; simplest build |
| Donations | EPC QR, no tracking | Users don't expect confirmation |
| High-value transactions | Option B — PISP | Verification and audit trail critical |
The underlying SEPA infrastructure — especially SCT Inst becoming mandatory across all EU banks — means bank-transfer payments with near-real-time confirmation are no longer aspirational. The tooling (neobank webhooks, PISP providers with proper webhook support) is mature enough to build on today.