Aller au contenu
IBANforge

API de validation de QR-IBAN suisse — résoudre un QR-IID

Une facture QR suisse porte un QR-IBAN, et un QR-IBAN n'est pas un IBAN suisse ordinaire sous un autre nom. Il identifie son établissement par une plage de numéros distincte, la plage QR-IID 30000–31999 que SIX réserve à l'émission de factures QR. Le même établissement répond donc à deux identifiants à la fois, et prendre l'un pour l'autre est la manière la plus courante de faire rejeter une coordonnée de paiement parfaitement correcte.

Cette page est la référence pour les trois questions qui en découlent : comment reconnaître un QR-IBAN, comment résoudre son QR-IID vers un établissement nommé, et ce qu'une validation CH/LI renvoie sans qu'on le demande. Toutes les réponses ci-dessous ont été capturées sur les données SIX BankMaster livrées avec l'API, aucune n'a été écrite à la main.

Un établissement, deux identifiants

Les positions 5 à 9 d'un IBAN suisse portent l'identifiant d'établissement (IID, aussi appelé numéro de clearing ou BC-Nummer). Pour les factures QR munies d'une référence QR, SIX attribue à l'établissement un second identifiant pris dans la plage réservée — et les deux nombres n'ont aucun lien, ni arithmétique ni de préfixe :

ÉtablissementClearing ordinaire (BC-Nummer)QR-IID
PostFinance AG0900030000
Valiant Bank AG0630030024
UBS Switzerland AG0023030005, 30308

Trois conséquences, dans l'ordre où elles mordent :

  1. Un QR-IID cherché dans une table de numéros de clearing ne donne rien. Conclure de cette absence que le QR-IBAN est mal formé revient à rejeter une instruction correcte — la panne la plus fréquente des intégrations de paiement suisses.
  2. C'est la plage qui décide du type de référence, pas la facture. Un IBAN dont l'IID tombe entre 30000 et 31999 exige une référence QR structurée ; un IBAN ordinaire accepte une référence créancier ou un message libre. Intervertir les deux fait refuser l'instruction à la soumission.
  3. Un établissement peut détenir plusieurs QR-IID. UBS en a deux. Un code qui suppose une valeur unique tronque l'ensemble en silence.

Sur les 1,100+ entrées de clearing suisses que nous livrons depuis le SIX BankMaster, 231 se trouvent dans la plage QR et 224 d'entre elles portent un BIC — mesuré sur le rafraîchissement 2026-08, et ce décompte bouge au gré des fusions et des changements de participation. Un identifiant de la plage QR derrière lequel il n'y a aucun établissement est une vraie réponse, pas une erreur : l'API répond found: false.

Étape 1 — reconnaître le QR-IBAN (gratuit)

GET /v1/iban/format décompose un IBAN sans rien consulter, et ne coûte rien :

curl "https://api.ibanforge.com/v1/iban/format?iban=CH5530024123000889012"
{
  "iban": "CH5530024123000889012",
  "formatted": "CH55 3002 4123 0008 8901 2",
  "valid": true,
  "check_digits": "55",
  "country": { "code": "CH", "name": "Switzerland" },
  "bban": { "bank_code": "30024", "account_number": "123000889012" },
  "upgrade_to_full_validation": "POST /v1/iban/validate ($0.005) — adds BIC, SEPA, VoP, sanctions, Swiss BC-Nummer."
}

bank_code vaut 30024 : dans la plage, donc c'est un QR-IBAN. La clé de contrôle est bonne, la structure est bonne — et vous ignorez toujours quel établissement l'a émis. Cela demande un registre.

Étape 2 — lookup de QR-IID (GET /v1/ch/clearing/:iid)

Le point d'entrée clearing accepte directement un QR-IID et fait pour vous la traduction entre les deux plages :

curl https://api.ibanforge.com/v1/ch/clearing/30024 \
  -H "Authorization: Bearer ifk_live_xxxxxxxxxxxxxxxxxxxx"
{
  "iid": "06300",
  "found": true,
  "institution": {
    "name": "Valiant Bank AG",
    "type": "bank",
    "iid_type": "other",
    "headquarters_iid": "06300"
  },
  "address": {
    "street": "Bundesplatz",
    "building_number": "4",
    "post_code": "3001",
    "town": "Bern",
    "country": "CH"
  },
  "bic": "VABECH22XXX",
  "payment_services": {
    "sic": true,
    "rtgs_chf": true,
    "instant_payments_chf": true,
    "eurosic": true,
    "lsv_bdd_chf": false,
    "lsv_bdd_eur": false
  },
  "sic_iid": "300240",
  "qr_iid": "30024",
  "qr_iid_source": "register",
  "valid_on": "2026-08-03",
  "cost_usdc": 0.003,
  "processing_ms": 0.06,
  "is_qr_iid": true,
  "note": "IID 30024 is a QR-IID (QR-bill range 30000–31999) of Valiant Bank AG; the institution's standard IID is 06300."
}

Lisez les premiers champs attentivement, leur sémantique est délibérée :

ChampSur un lookup de QR-IID
iidle numéro de clearing ordinaire de l'établissement (06300), jamais celui que vous avez interrogé. Vous renvoyer votre propre question vous laisserait la traduction sur les bras
qr_iidle QR-IID sur lequel portait la question (30024)
is_qr_iidtrue — posé uniquement quand l'identifiant interrogé est dans la plage QR, pour qu'un agent n'ait pas à connaître la convention de plages de SIX
notela même chose en prose, pour un LLM qui lit la réponse
qr_iid_sourceregister quand SIX publie l'appariement lui-même, headquarters quand il est hérité du siège de l'établissement (voir plus bas)
sic_iidle numéro de participant SIC à 6 chiffres de la ligne QR elle-même (300240), et non celui du clearing ordinaire affiché plus haut — ce dernier vaut 063000, et c'est lui que renvoie un lookup sur l'IID ordinaire
valid_onl'instantané BankMaster sur lequel la réponse est valable — les établissements fusionnent, arrimez-y vos attentes

Tarif. 0,003 $ par appel en x402, ou une unité du palier gratuit avec une clé d'API. La capture ci-dessus est un appel non authentifié tarifé en x402, d'où cost_usdc: 0.003 ; avec une clé couverte par son quota mensuel, le même champ revient à 0.

Un identifiant de la plage QR que SIX ne liste pas renvoie found: false avec error: "clearing_not_found" et un HTTP 200 — un résultat de recherche, pas un échec.

Le sens inverse — quel QR-IID cette banque détient-elle ?

SIX ne publie l'appariement que dans un sens : la ligne QR nomme l'établissement, aucune ligne ordinaire ne nomme son QR-IID. Nous l'indexons à l'envers, si bien qu'un IBAN suisse ordinaire répond lui aussi à la question — celle que se pose réellement une entreprise qui se met à émettre des factures QR. Voici le bloc clearing renvoyé pour l'IBAN UBS ordinaire CH1000230000000012345 :

{
  "iid": "00230",
  "name": "UBS Switzerland AG",
  "type": "bank",
  "town": "Zürich",
  "sic": true,
  "instant_payments_chf": true,
  "eurosic": true,
  "qr_iid": "30005",
  "qr_iid_source": "register",
  "qr_iids": ["30005", "30308"]
}

Deux champs portent l'honnêteté de cette réponse :

  • qr_iids apparaît quand SIX a attribué plus d'un QR-IID au même établissement. Le scalaire qr_iid garde le plus petit, pour qu'un code qui ne lit que ce champ obtienne quand même une valeur publiée plutôt qu'une troncature silencieuse.
  • qr_iid_source sépare deux affirmations de force différente. register est un appariement publié par SIX. headquarters signifie que la ligne est une succursale et que le QR-IID appartient à son siège — une déduction, solide puisque SIX attribue par établissement, mais une déduction. Servir les deux sans étiquette les tiendrait au même standard, ce qu'elles ne méritent pas.

Étape 3 — valider le QR-IBAN de bout en bout (POST /v1/iban/validate)

Pour CH et LI, un seul appel de validation embarque le bloc clearing. Pas de seconde requête, pas de découpage des positions 5 à 9 à faire soi-même :

curl -X POST https://api.ibanforge.com/v1/iban/validate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ifk_live_xxxxxxxxxxxxxxxxxxxx" \
  -d '{"iban": "CH5530024123000889012"}'
{
  "iban": "CH5530024123000889012",
  "valid": true,
  "country": { "code": "CH", "name": "Switzerland" },
  "check_digits": "55",
  "bban": { "bank_code": "30024", "account_number": "123000889012" },
  "sepa": { "member": true, "schemes": ["SCT", "SDD"], "vop_required": false, "vop_participant": false },
  "formatted": "CH55 3002 4123 0008 8901 2",
  "bic": {
    "code": "VABECH22",
    "bank_name": "Valiant Bank AG",
    "city": "Bern",
    "source": "IBANforge curated bank-code map",
    "as_of": "2026-08",
    "lei": "529900Z7NMGN5XV0RV34",
    "lei_status": "ACTIVE"
  },
  "issuer": { "type": "bank", "name": "Valiant Bank AG", "classification": "default" },
  "risk_indicators": {
    "issuer_type": "bank",
    "country_risk": "standard",
    "test_bic": false,
    "sepa_reachable": true,
    "sepa_reachable_scope": "country",
    "vop_coverage": false
  },
  "bank_code_check": {
    "value": "30024",
    "status": "verified",
    "match": "register",
    "register": "SIX BankMaster (Swiss IID / BC-Nummer register)",
    "authoritative": true,
    "institution": {
      "name": "Valiant Bank AG",
      "street": "Bundesplatz 4",
      "post_code": "3001",
      "town": "Bern",
      "country": "CH"
    },
    "as_of": "2026-08"
  },
  "clearing": {
    "iid": "06300",
    "name": "Valiant Bank AG",
    "type": "bank",
    "town": "Bern",
    "sic": true,
    "instant_payments_chf": true,
    "eurosic": true,
    "qr_iid": "30024",
    "qr_iid_source": "register",
    "is_qr_iid": true
  },
  "cost_usdc": 0.005,
  "processing_ms": 0.53
}

(Le bloc bic.address issu de GLEIF et le tableau next_steps sont omis ci-dessus pour la longueur ; les deux figurent dans la réponse réelle.)

bank_code_check.authoritative: true dit que le verdict vient de l'autorité d'attribution elle-même — le SIX BankMaster, et non un annuaire BIC qui mentionne au passage des banques suisses. is_qr_iid: true dans clearing marque l'IBAN comme QR-IBAN, tandis que iid porte déjà le numéro ordinaire de l'établissement.

Étape 4 — apparier la référence et le compte (reference_check)

Reconnaître un QR-IBAN ne fait que la moitié du travail. L'autre moitié, c'est la référence imprimée à côté, et les Swiss Payment Standards rendent les deux indissociables :

Une référence QRR (la référence QR structurée) ne peut être utilisée qu'en combinaison avec un QR-IBAN. Une référence créancier ISO 11649SCOR dans les Swiss Payment Standards — ne doit pas être utilisée avec un QR-IBAN.

— SIX, Swiss Implementation Guidelines Credit Transfer (pain.001), SPS 2026 v2.3, document daté du 20.02.2026, en vigueur au 14 novembre 2026 ; et SIX, Swiss Implementation Guidelines for the QR-bill v2.4 § 4.3.2 : « Use of the Creditor Reference (ISO 11649) presupposes that an IBAN has been used. A QR-IBAN cannot be used. »

Les guidelines marquent les violations de cette règle des codes d'erreur CH16 et CH17. Nous nommons ces codes parce qu'ils figurent dans la colonne des guidelines elles-mêmes ; nous n'en citons pas le libellé, qui vit dans un document de status report que nous n'avons pas lu. La réponse renvoie donc à « the Swiss Implementation Guidelines (SPS) » et s'arrête là.

Passez une reference à POST /v1/iban/validate et la réponse gagne un bloc reference_check qui porte deux verdicts indépendants :

VerdictCe à quoi il répond
validLa référence satisfait-elle sa propre règle de chiffre de contrôle ?
pairingA-t-elle le droit de voyager avec ce compte ?

Les deux ne bougent pas ensemble. Une référence peut être arithmétiquement parfaite et rester illicite sur cet IBAN — c'est précisément le cas que la règle existe pour attraper.

Les quatre issues d'appariement

pairingSignification
okLa combinaison est permise
qrr_requires_qr_ibanUne référence QR a été donnée pour un IBAN ordinaire
scor_forbidden_with_qr_ibanUne référence ISO 11649 a été donnée pour un QR-IBAN
not_applicableCompte hors CH/LI, ou schéma que la règle suisse ne couvre pas

Une référence QR sur le QR-IBAN auquel elle appartient :

curl -X POST https://api.ibanforge.com/v1/iban/validate \
  -H "Content-Type: application/json" \
  -d '{"iban":"CH4431999123000889012","reference":"210000000003139471430009017"}'
{
  "reference_check": {
    "reference": "210000000003139471430009017",
    "scheme": "qrr",
    "valid": true,
    "status": "checked",
    "check_digit_expected": "7",
    "source": "SIX Swiss Implementation Guidelines for the QR-bill v2.4 (document dated 24.02.2026, valid from 14 November 2026), Annex B \"Check digit calculation by modulo 10 recursive\".",
    "as_of": "2026-02",
    "pairing": "ok",
    "pairing_as_of": "2026-02"
  }
}

La même référence sur un IBAN suisse ordinaire — la panne que ce bloc existe pour attraper :

{
  "reference_check": {
    "scheme": "qrr",
    "valid": true,
    "pairing": "qrr_requires_qr_iban",
    "note": "… Pairing: IID 04835 is outside the SIX QR range 30000–31999, so this is an ordinary IBAN, and a QRR reference may only be used in combination with a QR-IBAN per the Swiss Implementation Guidelines (SPS). Either use the creditor's QR-IBAN or send this payment without a QRR reference."
  }
}

valid vaut toujours true. La référence est bonne ; c'est la combinaison qui ne l'est pas. Un code qui ne lit que valid expédie cette instruction et se la fait refuser à la soumission.

Hors de Suisse et du Liechtenstein, pairing vaut not_applicable — il n'y a aucun QR-IBAN contre lequel apparier, et répondre ok affirmerait un contrôle qui n'a jamais tourné. Le verdict de checksum de la référence, lui, n'est pas affecté : une référence RF valide est valide partout.

Les checksums de référence, seuls, sont gratuits

L'arithmétique est une commodité publiée, elle ne coûte donc rien :

curl "https://api.ibanforge.com/v1/reference/validate?reference=RF18539007547034"
{
  "reference": "RF18539007547034",
  "scheme": "rf",
  "valid": true,
  "status": "checked",
  "check_digit_expected": "18",
  "source": "Finance Finland, \"Structure of the RF Creditor Reference (ISO 11649)\", October 2023 (check-digit algorithm); SIX Swiss Implementation Guidelines for the QR-bill v2.4 § 2.12.2, valid from 14 November 2026 (structure).",
  "as_of": "2023-10"
}

Quatre schémas sont contrôlés arithmétiquement, chacun contre un document primaire qui publie la règle gratuitement :

SchémaRègleSource
RF / ISO 11649 (SCOR)mod 97-10 — la même arithmétique qu'un chiffre de contrôle d'IBANFinance Finland, oct. 2023
Référence QR suisse (QRR)27 chiffres, modulo 10 récursifSIX IG QR-facture v2.4, annexe B
OGM/VCS belge12 chiffres, modulo 97 sur les dix premiers, un reste de 0 s'écrivant 97Febelfin v3.3, 01-02-2019
Viitenumero finlandais4 à 20 chiffres, poids 7-3-1 depuis la droiteFinance Finland, 1er nov. 2009

Le KID norvégien et l'OCR suédois sont reconnus, jamais jugés. Ils répondent valid: null avec status: "unverifiable_without_creditor_config", parce que le type de modulus et la longueur admise sont configurés par compte créancier par la banque du bénéficiaire : ce ne sont pas des propriétés de la chaîne. Répondre false rejetterait des références parfaitement bonnes, donc nous ne le faisons pas. Ne relayez jamais un null à un utilisateur comme « invalide » — relayez que le contrôle exige la configuration de la banque du créancier.

Une ambiguïté mérite d'être connue. Seuls un RF initial et une longueur de 27 chiffres désignent un schéma sans équivoque. Une chaîne de 12 chiffres nue est simultanément un OGM belge et une longueur finlandaise licite : la réponse donne donc la lecture la plus spécifique et signale l'autre dans also_valid_as. Passez reference_type quand vous connaissez le pays.

Classification des IBAN virtuels et identification des utilisateurs finaux (art. 22(3) AMLR)

Le même bloc issuer qui affiche bank pour Valiant est celui qui signale ailleurs un émetteur d'IBAN virtuels. Cela dépasse la Suisse, à cause d'une obligation européenne précise.

Ce que dit le règlement. L'article 22(3) du règlement (UE) 2024/1624 — l'AMLR, applicable à partir du 10 juillet 2027 — impose aux établissements de crédit et aux établissements financiers d'obtenir les informations permettant d'identifier et de vérifier l'identité des personnes physiques ou morales qui utilisent les IBAN virtuels qu'ils émettent, ainsi que le compte bancaire ou de paiement associé. L'établissement qui tient le compte vers lequel un vIBAN redirige doit pouvoir obtenir cette information de l'établissement émetteur sans délai, et en tout état de cause dans les cinq jours ouvrables suivant sa demande.

Ce que cela implique en pratique. Les deux côtés d'un montage vIBAN ont besoin de savoir qui a émis l'identifiant qu'ils tiennent en main avant de pouvoir agir. Rien dans cet article ne fait d'une API de validation d'IBAN une partie à ce devoir — et rien ici ne constitue un conseil juridique — mais la première étape, purement factuelle, est un problème de classification : quel établissement se trouve derrière cet IBAN, et de quel type d'établissement s'agit-il ?

Ce que notre API apporte. issuer.type est un signal structurel, et issuer.classification dit ce qu'il vaut :

issuer.typeSignificationPertinence vIBAN
bankétablissement de crédit traditionnelémission de vIBAN possible, mais ce n'est pas la norme
digital_banknéobanqueélevée — ces acteurs émettent des vIBAN couramment
emiétablissement de monnaie électronique (EMI)élevée — la catégorie d'émetteurs de vIBAN dominante
payment_institutionétablissement de paiementélevée
nullaucun établissement n'a pu être étayé (par exemple le code banque n'est pas sur une liste nationale de fournisseurs émetteurs d'IBAN)inconnue, et la réponse le dit au lieu de deviner
issuer.classificationComment le lire
curatedidentification positive issue de listes EMI / néobanques / établissements de paiement tenues à jour. Vous pouvez compter dessus
defaultle type est retombé sur bank parce que la plupart des porteurs de BIC sont des banques. À traiter comme une présomption, pas comme un constat

Cette même classification alimente le score de risque de POST /v1/iban/compliance : un émetteur emi ajoute 10 points et le flag emi_issuer, un payment_institution en ajoute 15 avec le flag payment_institution_issuer. Voici les deux blocs que cet appel ajoute par-dessus la validation ci-dessus, capturés sur le même QR-IBAN suisse :

{
  "compliance": {
    "sanctions": {
      "country_sanctioned": false,
      "bank_sanctioned": false,
      "matched_lists": [],
      "fatf_status": "member",
      "bank_screened": true
    },
    "reachability": { "sepa_instant": false, "sct": true, "sdd": false, "screened": true },
    "vop": { "participant": false, "status": "not_found", "screened": true },
    "risk_score": 10,
    "risk_level": "low",
    "flags": ["no_sepa_instant", "no_vop"]
  },
  "meta": {
    "scope": "bank_bic_only",
    "disclaimer": "Informational triage only — NOT a regulated AML/CFT product. Sanctions screening is performed at the BANK (BIC8) level: it flags the holding institution, NOT the beneficiary / account-holder name. Most sanctions designations target persons and companies, which this does not screen. Use a regulated provider (Refinitiv, ComplyAdvantage, etc.) for name-level KYC/AML obligations.",
    "sanctions_as_of": "2026-08-24T15:52:44.509Z",
    "fatf_as_of": "2026-06",
    "sources": "EU,OFAC,UN,FATF,EPC-SCT,EPC-SCT_INST,EPC-SDD"
  }
}

Ce meta.disclaimer n'est pas un ornement et il n'est pas adouci ici : il s'agit d'un tri informatif, pas d'un produit AML/CFT réglementé. Le filtrage des sanctions s'opère au niveau de la banque (BIC8) sur les données OFAC, EU et UN — il signale l'établissement teneur, jamais le nom du bénéficiaire ou du titulaire. C'est un signal amont qui dit quel type d'établissement se tient derrière un identifiant ; l'identification des utilisateurs finaux au titre de l'art. 22(3) se joue chez l'établissement émetteur, avec des moyens que nous ne détenons ni ne remplaçons.

Étape 5 — contrôler toute la charge utile de la QR-facture (POST /v1/ch/qr-bill/check, gratuit)

Le texte contenu dans un code QR suisse (le « Swiss Payments Code », 31 lignes positionnelles de SPC à EPD) se contrôle en un appel : en-tête et version, IBAN du créancier et son appartenance à la plage QR-IID, la référence QRR / SCOR / NON et sa somme de contrôle, les règles d'appariement (un QR-IBAN exige QRR ; un IBAN ordinaire l'interdit), montant et monnaie, créancier final laissé vide, et ce que l'échéance SIX du 14 novembre 2026 rend urgent : les adresses du créancier et du débiteur final sont-elles structurées (type S) ou encore combinées (type K) ?

curl -s -X POST https://api.ibanforge.com/v1/ch/qr-bill/check \
  -H "Content-Type: application/json" \
  -d '{ "payload": "SPC\n0200\n1\nCH4431999123000889012\nS\nRobert Schneider AG\nRue du Lac\n1268\n2501\nBiel\nCH\n\n\n\n\n\n\n\n1949.75\nCHF\nS\nPia Rutschmann\nMarktgasse\n28\n9400\nRorschach\nCH\nQRR\n210000000003139471430009017\nOrder 15.06.2026\nEPD" }'

La réponse porte valid (aucun constat de niveau erreur), ready_for_2026_11_14 (valide et chaque adresse présente est de type S), une entrée findings par règle enfreinte avec sa source, et pour une adresse combinée un bloc proposed_structured : les champs de type S dérivés des deux lignes combinées, à relayer comme correctif. Les adresses de type K ont été retirées de la norme le 21 novembre 2025 ; dès le 14 novembre 2026 les banques ne traitent plus les ordres permanents et modèles de paiement qui s'appuient dessus.

C'est gratuit, pure évaluation de règles, sans base de données : la banque derrière l'IBAN et sa participation aux rails de paiement restent le travail de POST /v1/iban/validate. Le même contrôle est l'outil MCP check_swiss_qr_bill et la page /tools/qr-bill.

Les limites, dites franchement

  • L'établissement, jamais le compte ni son titulaire. Un QR-IID résolu nomme l'établissement émetteur. Il ne dit rien des douze chiffres qui le suivent dans l'IBAN, ni de la personne qui détient ce compte.
  • Le type de référence est une règle, pas une prédiction. Nous vous disons qu'un IBAN se trouve dans la plage QR et appelle donc une référence QR structurée. Qu'une instruction donnée soit acceptée en aval dépend de la banque du débiteur et de la référence elle-même.
  • Un checksum de référence ne prouve pas que la référence est la bonne. valid: true dit que les chiffres sont cohérents entre eux ; il ne dit rien sur la correspondance entre cette référence et la facture que le créancier attend de lettrer.
  • Deux schémas que nous refusons délibérément de juger. Le KID norvégien et l'OCR suédois sont configurés par compte créancier par la banque du bénéficiaire. Nous reconnaissons le format et nous nous arrêtons là, plutôt que de fabriquer un verdict que nous ne pouvons pas soutenir.
  • CH16 / CH17 sont nommés, jamais cités. Les codes figurent dans les guidelines ; leur libellé vit dans un document de status report que nous n'avons pas consulté.
  • Fraîcheur mensuelle, toujours datée. Le SIX BankMaster est rafraîchi chaque mois et chaque réponse clearing porte son valid_on. Un QR-IID valable il y a un an peut être redirigé aujourd'hui.
  • qr_iid_source: "headquarters" est une déduction. Solide, étiquetée, et jamais présentée comme un appariement publié par SIX.

Pour continuer