Skip to content Skip to footer

Payer par simple virement QR, gratuitement : pourquoi le Luxembourg attend encore — et l’outil que nous avons créé pour ne plus attendre

Chez oki.lu, nous générons chaque mois plusieurs milliers de factures pour des commerçants, artisans et indépendants luxembourgeois. Depuis des années, ces factures portent un QR-code de paiement Payconiq. Et depuis quelques mois, une même question revient dans toutes nos conversations avec nos clients : « et maintenant, on fait comment ? »

Digicash, Payconiq, Buckaroo : la troisième migration en quelques années

Les professionnels du pays connaissent la chanson. Il y a eu Digicash, la solution luxembourgeoise que tout le monde avait fini par adopter. Puis Digicash est devenu Payconiq : nouvelle intégration, nouvelles conditions. Aujourd’hui, Payconiq migre vers Buckaroo — et cette fois, le changement ne se limite pas au logo sur l’application.

Le modèle tarifaire bascule d’un coût fixe par transaction vers une commission proportionnelle au montant encaissé. Pour un commerce de proximité aux marges déjà comprimées, la différence n’est pas anecdotique : c’est une ponction récurrente sur chaque encaissement, qui s’ajoute aux frais des paiements par carte. Et surtout, c’est la démonstration d’une dépendance : chaque solution privée peut être rachetée, retarifée ou arrêtée du jour au lendemain, et les professionnels n’ont d’autre choix que de suivre.

Ce que nos clients nous demandent, ce n’est pas un énième prestataire. C’est une solution pérenne — une solution qui ne peut ni changer de mains, ni changer de prix, ni disparaître.

Cette solution existe. Elle est européenne, ouverte et gratuite.

Elle s’appelle le QR-code EPC (norme EPC069-12 du Conseil européen des paiements, connue en Allemagne sous le nom de Girocode). Le principe tient en une phrase : le QR-code contient les coordonnées du virement — bénéficiaire, IBAN, montant, communication — et le client le scanne directement dans son application bancaire, qui pré-remplit un virement SEPA. Il vérifie, il confirme, c’est payé.

Pas d’application supplémentaire à installer. Pas d’inscription. Pas d’intermédiaire qui touche les fonds. Et pas de commission : un virement SEPA ne coûte rien, et depuis le règlement européen sur les paiements instantanés, le virement instantané est facturé au même prix que le virement classique — c’est-à-dire, pour la quasi-totalité des comptes, zéro.

Les bénéfices sont partagés. Pour le client : un paiement en moins de trente secondes, sans saisie d’IBAN et sans risque d’erreur. Pour le professionnel : un coût d’encaissement nul et — c’est notre partie préférée, déformation d’éditeur de logiciel de facturation oblige — une réconciliation comptable automatisée : la référence de paiement contenue dans le QR revient intacte avec le virement, et chaque encaissement se rattache tout seul à sa facture.

Ça fonctionne déjà. Massivement. Juste pas ici.

Ce n’est pas une promesse de brochure. En Allemagne, la quasi-totalité des applications bancaires — Sparkasse, Volksbank, ING, Deutsche Bank, Commerzbank, DKB, N26 — scannent nativement ces QR-codes, présents sur des millions de factures. L’Autriche, où le standard est né, la Belgique, la Finlande et les Pays-Bas connaissent une adoption comparable.

Et au Luxembourg ? Le paradoxe est complet : les résidents clients de Revolut ou N26 peuvent déjà scanner un QR EPC aujourd’hui. Les clients des banques de la place, non — leurs applications n’ont tout simplement pas le lecteur. Le seul maillon manquant entre les professionnels luxembourgeois et un moyen d’encaissement gratuit et pérenne, c’est une fonctionnalité de quelques écrans dans les applications bancaires du pays.

Nous avons entrepris de le dire à qui de droit : la Chambre de Commerce, l’ABBL, le ministère de l’Économie, le ministère des Finances et les groupes parlementaires ont été saisis de la question. Nous vous tiendrons informés des réponses sur ce blog.

En attendant, nous avons construit l’outil. Il est gratuit.

Parce que la meilleure façon de faire avancer un standard, c’est de le rendre utilisable dès aujourd’hui, nous avons développé un générateur de QR EPC gratuit, sans inscription et sans aucune donnée stockée sur nos serveurs.

Il couvre trois usages :

Le QR de facture. Renseignez votre nom, votre IBAN, le montant et la communication : vous obtenez un QR-code conforme à la norme, à télécharger et à imprimer sur vos factures, vos devis ou votre comptoir. L’IBAN est vérifié automatiquement (somme de contrôle) pour éliminer toute erreur de saisie.

Le lien de paiement. L’outil génère aussi un lien à partager par email, WhatsApp ou SMS : votre client l’ouvre et trouve une page de paiement propre à votre nom, avec le QR et le mode d’emploi. Toutes les informations tiennent dans le lien lui-même — rien n’est enregistré chez nous, partagez-le comme vous partageriez un RIB.

La demande à montant libre. Laissez le montant vide et vous obtenez une page de don ou de participation libre : des boutons de montants suggérés, un champ libre, et le QR qui s’adapte instantanément. Idéal pour les associations, les clubs, les cagnottes et les pourboires.

👉 Essayez le générateur ici — et pour le tester en conditions réelles, scannez le résultat avec l’application Revolut ou N26 : le virement pré-rempli s’affiche en deux secondes.

Et si votre banque ne scanne pas encore ?

C’est précisément le sujet. Si vous êtes client d’une banque luxembourgeoise et que ce service vous semble aller de soi, dites-le-lui — les banques écoutent leurs clients bien plus que les éditeurs de logiciels. Si vous êtes commerçant, artisan ou responsable d’association et que ce standard répondrait à vos besoins, parlez-en autour de vous, et n’hésitez pas à nous écrire : chaque témoignage renforce le dossier que nous portons auprès des institutions.

Le virement instantané est devenu un droit européen. Il ne manque qu’un scanner.


oki.lu est un éditeur luxembourgeois de logiciels de facturation. Le générateur de QR EPC est et restera gratuit.

oki.lu · norme EPC069-12 · virement SEPA

API QR EPC — Documentation développeurs

Convertissez des coordonnées bancaires en QR-code de virement SEPA, scannable par n'importe quelle application bancaire compatible. Le client scanne, son virement est pré-rempli, il confirme. Aucune donnée n'est stockée côté serveur.

POST /qr-epc-api.php

§1Démarrage rapide

La réponse est directement une image PNG — pas de JSON, pas de base64.

bash
curl -X POST https://www.oki.lu/qr-epc-api.php \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Mon Entreprise Sarl",
        "iban": "LU120014123456789012",
        "amount": "49.90",
        "reference": "Facture 2026-001"
      }' \
  -o qr.png

§2Endpoint

URLhttps://www.oki.lu/qr-epc-api.php
MéthodePOST uniquement (OPTIONS supporté)
RequêteContent-Type: application/json
Réponse (succès)image/png
Réponse (erreur)application/json
AuthentificationAucune à ce jour
Taille max du corps20 000 octets

§3Paramètres du corps JSON

ChampTypeDescription
namestringrequisNom du bénéficiaire. Max 70 caractères.
ibanstringrequisIBAN du bénéficiaire, checksum validé (mod 97).
bicstringoptionnel8 ou 11 caractères. Requis si version="001".
amountstringoptionnelMontant EUR. Absent/vide = montant libre (don). 0,01 à 999 999 999,99.
referencestringoptionnelCommunication libre, max 140 car. Incompatible avec structured_reference.
structured_referencestringoptionnelRéférence ISO 11649 (RF..), checksum validé.
purposestringoptionnelCode SEPA 4 lettres (ex. GDSV).
versionstringoptionnel"001" ou "002" (défaut).
sizeintegeroptionnel3 à 20 px/module (défaut 8).
marginintegeroptionnel0 à 40 px (défaut 16).
Règle importante — reference et structured_reference sont mutuellement exclusifs (erreur 422 si les deux sont envoyés).

§4Réponses & erreurs

200 OK Succès

Corps : PNG brut. En-tête utile :

headers
Content-Type: image/png
X-EPC-Payload-Bytes: 64

X-EPC-Payload-Bytes — la spec recommande de rester sous 331 octets pour une lecture fiable.

Codes d'erreur

CodeCas
400Corps vide, ou JSON malformé
405Méthode autre que POST/OPTIONS
413Corps > 20 000 octets
422Champ(s) invalide(s) — détail dans le message
500Erreur serveur
json — exemple d'erreur
{"error": "iban manquant ou invalide (checksum). bic invalide (8 ou 11 caractères)."}

§5Exemples

Montant fixe (facture)

bash
curl -X POST https://www.oki.lu/qr-epc-api.php \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Mon Entreprise Sarl",
        "iban": "LU120014123456789012",
        "amount": "149.00",
        "reference": "Facture 2026-042"
      }' \
  -o facture-042.png

Montant libre (don)

Omettez simplement amount.

bash
curl -X POST https://www.oki.lu/qr-epc-api.php \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Association Les Amis du Quartier",
        "iban": "LU280019400644750000",
        "reference": "Don libre"
      }' \
  -o don.png

Référence structurée (rapprochement automatisé)

bash
curl -X POST https://www.oki.lu/qr-epc-api.php \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Mon Entreprise Sarl",
        "iban": "LU120014123456789012",
        "amount": "89.50",
        "structured_reference": "RF18539007547034"
      }' \
  -o facture-rf.png

Haute résolution (impression)

bash
curl -X POST https://www.oki.lu/qr-epc-api.php \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Mon Entreprise Sarl",
        "iban": "LU120014123456789012",
        "amount": "25.00",
        "size": 14,
        "margin": 30
      }' \
  -o qr-print.png

§6Intégration PHP

php
<?php
$payload = json_encode([
    'name'   => 'Mon Entreprise Sarl',
    'iban'   => 'LU120014123456789012',
    'amount' => '49.90',
    'reference' => 'Facture 2026-001',
]);

$ch = curl_init('https://www.oki.lu/qr-epc-api.php');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $payload,
    CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
    CURLOPT_RETURNTRANSFER => true,
]);
$png = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode === 200) {
    file_put_contents('qr.png', $png);
} else {
    $err = json_decode($png, true);
    error_log('Erreur QR EPC : ' . ($err['error'] ?? 'inconnue'));
}

§7Intégration JavaScript

javascript
const res = await fetch('https://www.oki.lu/qr-epc-api.php', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'Mon Entreprise Sarl',
    iban: 'LU120014123456789012',
    amount: '49.90',
    reference: 'Facture 2026-001',
  }),
});

if (res.ok) {
  const blob = await res.blob();
  const url = URL.createObjectURL(blob);
  document.querySelector('#qr').src = url;   // <img id="qr">
} else {
  const { error } = await res.json();
  console.error('Erreur QR EPC :', error);
}
Pour afficher le QR comme un simple <img>, faites transiter l'appel par votre backend, qui appelle l'API en POST et retransmet le PNG — cela évite d'exposer un IBAN en clair dans une URL GET loguée.

§8Bonnes pratiques

🔒 Jamais en GET

Ne mettez jamais l'IBAN ou le montant dans une URL loguée. L'API n'accepte que POST pour cette raison.

⚡ Sortie déterministe

Un PNG généré avec des paramètres identiques est toujours identique — cache possible par clé iban+amount+reference.

🖨️ Choisir size

8 pour écran/PDF ; 12–16 pour de l'impression grand format.

🔁 Préférer la référence structurée

Dès que possible, structured_reference est plus fiable qu'un texte libre.

§9Limites connues

Pas de webhook ni de statut de paiement. Le rapprochement se fait de votre côté (relevés bancaires, référence structurée).
Couverture bancaire — excellente en Allemagne, Autriche, Belgique, Finlande, Pays-Bas et néobanques (Revolut, N26) ; quasi absente en France, Espagne, Italie à ce jour.
Pas d'authentification actuellement — prévoyez un proxy avec limitation de débit pour un usage public à fort volume.

§10Aide-mémoire

référence rapide
POST /qr-epc-api.php
Content-Type: application/json

{
  "name": "string, requis, max 70",
  "iban": "string, requis, IBAN valide",
  "bic": "string, optionnel, requis si version=001",
  "amount": "string, optionnel — vide = montant libre",
  "reference": "string, optionnel, max 140 — XOR structured_reference",
  "structured_reference": "string, optionnel, format RF.. — XOR reference",
  "purpose": "string, optionnel, 4 lettres",
  "version": "\"001\" | \"002\", défaut \"002\"",
  "size": "int 3–20, défaut 8",
  "margin": "int 0–40, défaut 16"
}

→ 200  image/png
→ 4xx/5xx  {"error": "..."}
QR conforme à la norme européenne EPC069-12 (Girocode) · API sans état · oki.lu

Leave a comment

Custom Software Development
Agence de marketing digital et développement de logiciels d’entreprise à Luxembourg.

Oki © 2026. All Rights Reserved.

Aller au contenu principal