The single most common integration bug with Verification of Payee is treating a NO_MATCH as a failed request. It isn't. A successful verification that happens to say 'this name does not belong to this IBAN' is still a 200 response with useful data. Confuse the two and you'll either swallow fraud signals or show users scary errors.
The four scheme codes
Every Verification of Payee response maps to one of four standardised SEPA scheme codes. Branch on the code, not on free-text:
- MTCH — MATCH: the name matches the account holder. Proceed.
- CMTC — CLOSE_MATCH: almost right (missing middle name, trading vs legal name). Show the suggested verified name and ask the payer to confirm.
- NMTC — NO_MATCH: the name does not belong to the IBAN. Warn clearly and block auto-approval.
- NOAP — NOT_APPLICABLE: the check couldn't be completed (e.g. responding bank unreachable). Let the user decide with extra caution.
Result vs error
If the HTTP status is 200, you have a verification result — read scheme_code. If it's 4xx/5xx, you have an error — read the error code. Never map NO_MATCH onto your error path.
Handling CLOSE_MATCH well
CLOSE_MATCH is where good UX is won or lost. The response can carry the verified account-holder name; surface it as a suggestion ('Did you mean…?') so the payer confirms or corrects rather than abandoning the payment. Treating CMTC as a hard failure frustrates legitimate users.
Genuine error codes
Separate from scheme outcomes, transport-level problems return standard HTTP errors — for example invalid_iban (400), unauthorized (401), rate_limited (429) and scheme_unavailable (503). Each carries a request id so support can trace it. Pass a stable external id on every call so retries stay idempotent and logs reconcile.