Use case · Finance & Payments
Import a bank account file and catch the bad IBANs first.
A supplier or counterparty account list is a payment incident waiting to happen. Map it to bank_accounts_v1, have every IBAN checked mod-97 and every BIC checked by format, and get the review flag on every run.
The job
What you are actually trying to get done
Before you can pay anyone you have to load their account details, and a wrong IBAN does not fail politely — it either bounces days later or pays the wrong account. The job is to get a hand-maintained list into one shape and have every identifier checked by its own checksum before it reaches a payment file.
Where it lands
Bank accounts
bank_accounts_v1 · risk: high
iban and bic are two distinct validator types. iban computes mod-97 and checks the country against this template’s list (CH, LI, DE, FR, IT, ES); bic checks BIC format. Legacy account_number and routing_number are carried as strings — they have no universal checksum to enforce.
Canonical columns
- account_holder
- iban
- bic
- account_number
- routing_number
- currency
6 canonical columns · 2 required · 2 validated
Step by step
The whole run, one call at a time
- 1
Upload the list
CSV, Excel, JSON, XML, Parquet or a SQL dump. All parsed in-process — no bytes leave to read a tabular file, in either mode.POST /v1/uploads - 2
Map the German banking vocabulary
Kontoinhaber→account_holder,SWIFT→bic,Kontonummer→account_number,BLZ→routing_number— all shipped hints, all layer 2, all free.POST /v1/uploads/:id/match - 3
Run the checksums
Every IBAN is checked mod-97 and against the country list; every BIC by format. The transposed digit fails here, in a response with a row index, rather than in a bank rejection three days later.POST /v1/uploads/:id/validate - 4
Hold the batch for a human
bank_accounts_v1is high-risk, so the mapping always comes backpending_review. That is a property of the template, not a setting — it applies on every call, in every workspace.requires_hitl: true - 5
Deliver the clean set
skip_invalid_rows: truecommits what passed and returns the rest inskipped. Output as rows, a file, a signed webhook, or a direct write into your database.POST /v1/uploads/:id/commit
In code
One stateless row check
POST /v1/validate-row is a stateless helper — no upload, no session — for checking a single record against a template’s validators. It is one of the two no-key MCP tools.
curl https://api.adaptivmapr.com/v1/validate-row \
-H "Content-Type: application/json" \
-d '{
"template_id": "bank_accounts_v1",
"row": {
"account_holder": "Muster AG",
"iban": "CH93 0076 2011 6238 5295 8",
"bic": "UBSWCHZH80A",
"currency": "CHF"
}
}'{
"template_id": "bank_accounts_v1",
"valid": true,
"errors": [],
"warnings": []
}- Nineteen validator types ship. The checksum-strict ones —
iban(mod-97),gtin(GS1 check digit),npi(Luhn),gln(13-digit GS1) — actually compute the check digit rather than matching a pattern. bank_accounts_v1is one of five high-risk templates. The other four arepayments_v1,kyc_profiles_v1,employees_v1andpayroll_v1.- Connector secrets — a treasury API token, a database credential — are KEK-encrypted at rest and readable only through the service-role plane, never through the user-JWT dashboard plane.
- The rate limiter is two-tier: a shared Postgres counter is authoritative per fixed window, with a per-isolate in-process map as a fast pre-deny and a fail-open fallback when the shared store is unreachable.
Where the work lands
Which layer resolves this file
| Layer | What it does here | Auto-accepts at | Cost |
|---|---|---|---|
| 1 · statistics | Header→field pairs confirmed on earlier counterparty loads | ≥100 @ 95% · ≥20 @ 100% | Free · deterministic |
| 2 · heuristic | “Kontoinhaber”, “SWIFT”, “Kontonummer”, “BLZ”, “Währung” — shipped hints | ≥ 0.85 | Free · deterministic |
| 3 · fuzzy | “IBAN Nr.”, “Acct #” and other punctuated variants after normalization | ≥ 0.80 | Free · pure compute |
| 4 · semantic | A treasury-system label with no shared vocabulary | ≥ 0.78 | Cheap, cached · off without an embedding key |
| 5 · ai | One batched call over anything left, told which fields are already claimed | Model pick, constrained to the unclaimed column set | Metered · the only paid layer |
MAPR_EMBEDDING_API_KEY, MAPR_LLM_API_KEY) and fail soft to OFF, so an unconfigured deployment still maps on the deterministic layers rather than erroring.Before you commit
Review, cost and where it routes
It comes back flagged for review
bank_accounts_v1 is a high-risk template, so PATCH /v1/uploads/:id/mappings returns requires_hitl: true and hitl_status: "pending_review" on every call, for every workspace, with nothing to configure.
Honest limitThe flag is derived from the template’s risk field and is advisory in v1 — we set it, your workflow owns the queue. The upload is not server-side blocked. A native AgentGate approval queue is roadmap, not v1.
Usually just the flat fee
When every column resolves on layers 1–3 — the common case for a file you receive regularly — no model runs, so there are no AI tokens to bill. A small flat per-map fee ($0.0010) is drawn on every map — a fully deterministic one and a layout-cache re-map included. There is no free tier and no seats or contract; you top up a prepaid wallet from $10 and it draws down.
Rate cardAI tokens are billed only when a model actually ran, at provider cost ×2 (×0.5 with your own LLM key). A PHI-routed run multiplies the whole charge — flat fee included — by 1.2. See lib/pricing.ts and GET /v1/pricing.
Standard routing, region still pinned
This job carries no protected health information, so it runs on standard routing with no surcharge. The workspace region pin still applies — the routing class picks the model catalogue; the region decides where compute may run.
MechanismresolveRunPhi() in lib/agreements.ts resolves the axis per run from phi_mode in the body, falling back to tenants.phi_mode (default false). PHI is available on this job too if your data class calls for it — it costs +20% and needs the BAA.
Questions
The things people actually ask
Does a valid IBAN mean the account exists?
Our file mixes IBANs with legacy account numbers. Does that break it?
Can we point this at our treasury system instead of uploading files?
Does this handle card data?
Stop hand-mapping this file. Map it once.
Start with a $10 prepaid wallet. In schema-only mode only headers and up to three sample rows — each cell clamped to 80 characters — ever leave you.