# Pre-flight a bank transfer before an agent sends it > IBAN validity, bank and BIC, SEPA reachability, sanctions on the bank, its jurisdiction and the beneficiary name — one call, one verdict, and the reason behind it. Published 2026-08-10 · Updated 2026-08-16 · HTML version: https://invoket.com/blog/pre-flight-a-bank-transfer-before-an-agent-sends-it --- An agent about to move money has to clear four separate questions before it builds the payment instruction: is this IBAN real, which bank is behind it and can that bank actually be reached on the scheme I intend to use, is the bank or its country under sanctions, and is the beneficiary name on a designation list. [`GET /preflight/payment`](/docs/api/preflight-payment) answers all four in one call and returns **one verdict** — `ok`, `review`, `stop` or `insufficient_coverage` — with every reason attached to the block and the dated source it came from. The rule that makes the verdict worth reading is the same one that governs its counterparty sibling: **`ok` is impossible while any block is short of coverage.** A check that did not happen never passes. ## The question your bank's Verification of Payee does not answer Since **9 October 2025**, payment service providers in euro-area member states must offer Verification of Payee free of charge on euro credit transfers, instant and standard alike, telling the payer whether the payee name matches the IBAN before the transfer is authorised ([European Commission](https://finance.ec.europa.eu/news/new-eu-rules-make-instant-euro-payments-faster-and-safer-2025-10-10_en)); PSPs outside the euro area follow in July 2027. That is a real improvement, and it makes one specific failure mode — a correct-looking name pointed at somebody else's account — much harder. It is also a different question from this one. VoP asks *does this account belong to the party you named*. It does not ask *should you be sending money to that party at all*, and it happens at the very end of the flow, inside your bank, after the agent has already decided who to pay. A designated entity that gives you its own genuine IBAN passes VoP cleanly. The scale of what sits behind that gap is not speculative. Payment fraud across the EEA reached **€4.2 billion in 2024**, of which **€2.2 billion on credit transfers**, up 16% year on year — and payment service users, not their banks, bore roughly **85%** of credit-transfer fraud losses, "mainly as a result of scams that tricked users into initiating fraudulent transactions" ([joint EBA–ECB report on payment fraud, 15 December 2025](https://www.ecb.europa.eu/press/pr/date/2025/html/ecb.pr251215~e133d9d683.en.html)). Those are authorised transfers. The control that would have caught them belongs *before* the instruction exists — which is exactly where an autonomous agent operates, and exactly where a pre-flight call fits. ## One call, three checks, and the part you would otherwise write yourself The endpoint runs the work of [`GET /iban/resolve`](/docs/api/iban-resolve), [`GET /iban/screen`](/docs/api/iban-screen) and [`GET /screen/entity`](/docs/api/screen-entity) in one round-trip and **one x402 settlement**. Each block keeps the **exact shape of its standalone endpoint** — nothing flattened, nothing summarised away — so the composite adds information rather than replacing it. What it adds is the piece you would otherwise have to write and keep correct: the decision table that turns three independent answers into one verdict, including an explicit rule for what happens when a check could not run. The verdict is always **exactly the maximum severity among the listed reasons**, and every reason carries its block, a stable code from a closed set of ten, and its own severity. An agent can therefore **recompute the verdict from the blocks** instead of trusting it. | `verdict` | What it means | |-------------------------|---------------------------------------------------------------------------------------------| | `stop` | Invalid IBAN, sanctioned bank or BIC, embargoed jurisdiction, or a hit on the beneficiary name | | `review` | Bank unknown in a **complete** national registry, high-risk or monitored jurisdiction, or a weak name match | | `insufficient_coverage` | No signal — but a check did not happen | | `ok` | Every check ran, and none of them raised a signal | ## A clean account at a clean bank can still be a `stop` The case worth internalising is the one where the two easy checks pass and the transfer is still refused. Abridged from [the production capture on the doc page](/docs/api/preflight-payment#stop--the-beneficiary-is-on-the-lists): ```json { "verdict": "stop", "verdict_reasons": [ { "block": "name_screening", "code": "NAME_HIT", "severity": "stop", "detail": "the beneficiary name matches a designated entity" } ], "iban": { "valid": true, "country": "DE", "coverage": "full", "bank": { "name": "Commerzbank", "bic": "COBADEFFXXX" }, "reachable": true }, "bank_screening": { "coverage": "screened", "screening": { "risk": "clear", "bank_sanctioned": false, "jurisdiction": { "level": "clear", "lists": [] }, "hits": [] } }, "name_screening": { "coverage": "screened", "screening": { "verdict": "hit", "verdict_basis": ["exact", "exact_alias"], "hits": [ { "id": "OFAC-SDN:25684", "list_source": "OFAC-SDN", "matched_name": "EUROPAISCH-IRANISCHE HANDELSBANK AG", "match_type": "exact", "programs": ["IFSR", "IRAN", "NPWMD"], "listed_on": "2018-11-05" }, { "id": "EU:EU.13742.32", "list_source": "EU-FSF", "matched_name": "Europäisch-Iranische Handelsbank", "match_type": "exact_alias", "programs": ["IRN"], "listed_on": "2025-09-29" } ] } } } ``` A valid German IBAN, a large clean bank, full registry coverage — and a `stop` on the beneficiary alone, sourced to two lists with their programmes and designation dates. Note that the two blocks that passed are **still returned in full**: the verdict never erases the evidence it was computed from. ## Two distinctions that a naive aggregator collapses **A gap is not a pass.** Omitting `beneficiary_name` is allowed, and it forbids `ok` — the name block comes back `not_requested`, which is a coverage gap, not a clearance. An `ok` there would read as a green light on a beneficiary nobody looked at. The same applies to an IBAN whose country no registry covers: the bank block is `insufficient_coverage`, its `risk` is `"unknown"`, and **`unknown` must never be read as `clear`**. Absence of a hit is not evidence of absence when nothing was searched. **A gap is also not a signal.** The invalid-IBAN case makes the difference concrete: change one digit and `bank_screening.coverage` becomes `not_applicable` — there is genuinely nothing to screen — yet the verdict is `stop`, not `insufficient_coverage`. The verdict is the maximum severity, and a structurally broken IBAN is a signal about the instruction, not a hole in the analysis. ## Reachability is an operational answer, not a compliance one The IBAN block carries per-scheme SEPA reachability from the EPC register — `sct`, `sct_inst`, `sdd_core`, `sdd_b2b` — and none of it moves the verdict. It answers a different failure: the transfer that is perfectly legitimate and simply will not execute the way the agent planned it. That matters more than it used to, now that instant euro transfers are a standing obligation rather than a premium option: an agent that assumes SCT Inst on an account reachable only for standard SCT has built an instruction its own bank will not run as intended. ## `include_weak` is where your policy lives Weak matches — a source-flagged weak alias, or partial token coverage — are **always returned**. The `include_weak` flag only decides whether they count towards the verdict. Left at its default, a weak name match is a `review`; set to `true`, the same call returns the **same hits** with a verdict of `stop`. This is the one deliberately tunable line in the endpoint, and it is tunable in one direction only: the flag can make the service stricter, never blinder. A payout agent operating unattended can turn it on and treat `review` as a genuinely rare human escalation; a workflow with a reviewer in the loop can leave it off and read the hits itself. ## The payment loop 1. **Call the pre-flight before you build the instruction**, not after — the whole point is that it runs while a decision is still cheap to change. 2. **Always pass `beneficiary_name`.** It is optional in the contract and mandatory in practice: without it, `ok` is unreachable and you have paid for an answer with a known hole in it. 3. **Pass `country` only as a declaration.** It filters name candidates by the beneficiary's declared country and can only *remove* candidates whose country the list published in comparable form — a designation that publishes no country stays a candidate. 4. **Branch on the verdict, not on a score.** There is no numeric risk score to threshold, by design. `stop` and `review` are decisions; `insufficient_coverage` is a named open question, and it names *which* one. 5. **Persist the response, not a boolean.** Every block carries the snapshot date it was answered from, and the root `provenance` deliberately reports the **oldest** of them — the honest freshness of the answer as a whole. Six months later, "why did the agent send this payment" is answerable from stored, dated facts. The payment side of that loop is the ordinary discover → `402` → pay → replay cycle; the [Quickstart](/docs/quickstart) walks it with runnable snippets, and [For agents](/docs/for-agents) covers the discovery surfaces. ## Billing: a refused transfer is a successful answer The x402 golden rule is that the agent pays for the *answer to its question*, and here the mapping is unusually clean. "This IBAN fails its checksum" is a **useful answer** — HTTP **200** with a motivated `stop`, and it is billed. So are `review` and `insufficient_coverage`, because all three are answers. The 4xx range is reserved for requests the service cannot answer at all: a missing `iban`, or a `beneficiary_name` outside 2–200 characters. This endpoint is not priced at the catalog's flat per-call rate, and that is deliberate: one call runs three checks and the decision table over them, in one settlement. **No price appears in this article** — the gateway's [`/catalog`](https://api.invoket.com/catalog) is the single source of truth for every amount and every accepted rail, the three unit endpoints included, so compare them there. ## What it will not do - **It is not Verification of Payee.** The beneficiary name is compared against *designation lists*, never against the account holder's name held by the beneficiary bank. "Is this account really theirs?" is your PSP's question under the Instant Payments Regulation, and this endpoint does not answer it. - **No company due diligence.** Identity, insolvency, VAT status, e-invoicing reachability and control chain belong to [`GET /preflight/supplier`](/docs/api/preflight-supplier) — which will attach a whole payment pre-flight as its `bank` block when you pass it an `iban`. - **No PEP screening, no adverse media, no transaction analysis.** The name check covers the official designation lists in full — OFAC SDN and Consolidated, the EU financial sanctions list, the UN Security Council list — and nothing beyond them. - **No risk score, and no payment instruction.** Every response carries this verbatim in `data.limits`: the verdict is a control outcome, and the decision to pay remains the caller's. That scope sentence travels with every response rather than living in a footnote, so the agent and its auditor read the same statement. For the parameter contract, the full verdict and reason-code tables, the coverage states and the error codes, see the [`GET /preflight/payment` documentation](/docs/api/preflight-payment).