Screen a vendor file of IBANs in bulk, up to 500 per call

Bulk IBAN sanctions screening before a payout or an onboarding run: up to 500 counterparty IBANs cleared for sanctioned banks and jurisdiction risk in one request, against a single dated snapshot.

By Matthias Begot · · Updated

KYB is list-shaped. An agent onboarding a supplier file, preparing a payroll run, or re-clearing an existing counterparty book is never asking about one IBAN — it is asking about hundreds. One paid call — POST /iban/screen/batch — screens up to 500 IBANs for sanctioned banks/BICs (OFAC / EU / UN) and jurisdiction risk (FATF black/grey, embargoes, EU-AML) in a single request, settled as one x402 payment for the whole batch and answered from a single, dated snapshot of the lists.

The problem: counterparty screening comes in files, not questions

The single-IBAN gate is covered in Sanctions-screen a beneficiary IBAN before an agent pays it: before disbursing to one beneficiary, clear its bank and jurisdiction. But the inputs that actually reach a compliance-minded agent are lists — a CSV of vendor bank details, the beneficiary column of a payment file, the full book of counterparties a policy says must be re-checked. Looping GET /iban/screen over 500 rows means 500 HTTP round-trips, 500 402 challenges and 500 settlements — a per-row toll where the workflow needs a single gate before the run.

There is a second, less obvious problem: looping takes time, and the lists move underneath the loop. OFAC publishes changes to its sanctions lists continuously, on no fixed schedule; the FATF revises its high-risk and monitored jurisdictions at each plenary — the June 2026 plenary added Iraq and Bosnia and Herzegovina to the grey list and removed Algeria and Namibia. A batch screened row by row over a long window is not guaranteed to have been screened against one consistent state of the world.

The call: one JSON array, up to 500 IBANs

POST /iban/screen/batch takes a JSON body with a single field: ibans, an array of 1 to 500 strings. Spaces and dashes are tolerated, case does not matter — paste the column as it came out of the file.

POST /iban/screen/batch
Content-Type: application/json
{
  "ibans": [
    "DE89 3704 0044 0532 0130 00",
    "FR14 2004 1010 0505 0001 3M02 606",
    "not-an-iban"
  ]
}

A malformed entry inside the array is not a request error. It is screened like in the single call and comes back as its own row (valid: false, screening: null, with an issue code) — one bad row never fails the file.

What comes back: one verdict per row, one snapshot for the run

The response is the standard UnifiedResponse: a data block with count and results[], plus one provenance block. Three properties make it usable as a pre-run gate:

  • Order is preserved. results[] comes back in the same order as the input, and each element carries its own iban field, so the agent can re-pair verdicts with file rows without tracking indices.
  • Each row is a full ScreenResult. The same shape as the single call: resolved bank and BIC, whether the bank/BIC matched a sanctions list, the jurisdiction level, and the aggregated risk band — prohibited, high, elevated, clear, or unknown. The band semantics are documented in the single-call reference.
  • One provenance covers the whole batch. Every IBAN in the call is screened against the same lists snapshot, and provenance.freshness.as_of dates it. That is the consistency the row-by-row loop cannot give: the whole run cleared against one stated state of the lists, with a date the agent can log next to the payment file.

The agent’s branch logic is then a fold over the rows: stop the run (or pull the row) on prohibited, escalate high and elevated to policy, and treat unknown as not cleared — the service refuses to assert clear without data behind it. In particular, clear requires full coverage: an unsignalled IBAN under partial coverage (FR / GB / PT) or structure_only coverage is unknown, never clear. Each row carries its own coverage field so the agent knows which verdicts are load-bearing.

The x402 golden rule, applied to a file

The agent pays for the answer to its question, and “12 of your 500 counterparties are risky, 3 rows are not valid IBANs” is a successful answer. A well-formed batch returns 200 whatever the mix of clean, risky and invalid rows. Only requests the service cannot answer leave the 200 range: a missing or malformed body, an empty array, or a batch over the 500 cap — and the cap is checked before any screening, so an oversized file is rejected without being billed.

The batch is settled as one x402 payment and priced per IBAN by the gateway — the price scales with the number of rows, not the number of calls. As always, the authoritative figure and the accepted rails are served live by the catalog, never hardcoded here. The payment loop itself is the same discover → 402 → pay → replay cycle as every Invoket endpoint; the Quickstart walks it with runnable snippets and For agents covers the discovery surfaces.

A concrete shape: the pre-payment-run gate

A payout agent holding a 400-row supplier file runs the gate like this:

  1. Extract the IBAN column, as-is — no need to normalize spacing or case.
  2. Screen the file: one POST /iban/screen/batch, one 402, one signature, one replay.
  3. Fold the verdicts: quarantine prohibited and invalid rows, route high / elevated / unknown to policy or human review, keep clear rows (with full coverage) in the run.
  4. Log provenance.freshness.as_of with the run — the audit answer to “screened against which state of the lists?”.
  5. Pay the surviving rows through your own rails.

Because the lists move — continuously on the sanctions side, plenary by plenary on the FATF side — the same call is also the re-screening primitive: a policy that re-clears the whole counterparty book after each FATF list revision is one scheduled batch call, not a re-onboarding project.

What this gate does not do

The scope is exactly the single call’s scope, stated in its documentation:

  • It screens the bank/BIC against sanctions lists and the jurisdiction risk — it does not screen account-holder names. Payee-name checking is out of scope for this endpoint.
  • A clear row means no signal on the covered lists as of the snapshot date — it is not a legal compliance opinion and does not discharge your own AML obligations.
  • If what the file needs first is bank/BIC resolution rather than screening, POST /iban/resolve/batch is the companion batch for that job.

Used for what it is — one settled call that clears a whole file against one dated snapshot of the sanctions and jurisdiction lists — the batch turns counterparty screening from a per-row toll into a gate an agent can afford to run before every payment run. For the request contract, field tables and error codes, see the POST /iban/screen/batch documentation.