Use case · Finance & Payments

Import a processor settlement file without touching a full PAN.

Processors export settlements in their own shape. Map them to payments_v1 — brand, last four digits, amount, currency, status, processor reference — with the template built so a full card number has nowhere to land.

template_id: payments_v1
settlement_20260214.csv

What you actually get sent

  • txn_ref
  • card_type
  • last4
  • amt
  • ccy
  • state
  • captured

Abbreviated processor headers, an amount in minor units, a state vocabulary that is nearly but not quite the one your ledger uses.

The job

What you are actually trying to get done

Reconciling a processor settlement starts with getting the file into your own shape, and the constraint that makes it awkward is scope: whatever you build must not become a place a full card number can land. The job is to normalise brand, last four, amount, currency, status and reference — and nothing else.

Where it lands

Payments

payments_v1 · risk: high

card_last4 is constrained by a regex validator of exactly ^\d{4}$ — four digits, no more. There is no PAN field on this template, so a full card number has nowhere to map and is reported as unmapped rather than quietly carried through. That is the PCI posture, expressed in the schema rather than in a policy document.

The full field table →

Canonical columns

  • card_last4
  • card_brand
  • amount
  • currency
  • status
  • processor_ref
  • captured_at

7 canonical columns · 3 required · 1 validated

Step by step

The whole run, one call at a time

  1. 1

    Upload the settlement

    Parsed in-process. Nothing about a tabular file egresses in either mode — the parse happens inside the Worker, on your bytes.
    POST /v1/uploads
  2. 2

    Map the abbreviations

    last4 reaches card_last4 through the shipped last 4 hint; ccy reaches currency on the fuzzy layer; amt reaches amount. A column named pan or card_number reaches nothing, by design.
    POST /v1/uploads/:id/match
  3. 3

    Normalise the status vocabulary

    status is an enum, so a processor’s SETTLED or CAP either maps to one of the four values or fails validation loudly. An unrecognised state does not become a silent new category in your ledger.
    enum: authorized | captured | refunded | failed
  4. 4

    Validate the masked fields

    card_last4 against its four-digit regex, amount as a number, captured_at as a date. Failures come back per row with the field named.
    POST /v1/uploads/:id/validate
  5. 5

    Land it in your ledger

    Commit inline, as a file, over a signed webhook, or straight into a destination connector. Reconciliation logic is yours — this gets the file into the shape your reconciliation reads.
    POST /v1/uploads/:id/commit

In code

Settlement CSV in, ledger rows out

One call runs upload, match and validate and returns the transformed grid, with an optional serialized file attached to the same envelope.

curl
curl https://api.adaptivmapr.com/v1/transform \
  -H "Authorization: Bearer $ADAPTIVMAPR_API_KEY" \
  -F "file=@settlement_20260214.csv" \
  -F "template_id=payments_v1" \
  -F "output=sql"
response
{
  "ok": true,
  "target_schema_id": "payments_v1",
  "transformed": {
    "headers": ["card_last4", "card_brand", "amount", "currency", "status", "processor_ref", "captured_at"],
    "rows": [["4242", "visa", "129.90", "CHF", "captured", "ch_3Q…", "2026-02-14"]]
  },
  "errors": [],
  "skipped": 0,
  "file": { "format": "sql", "filename": "payments_v1.sql", "content_type": "application/sql", "data": "CREATE TABLE IF NOT EXISTS payments_v1 (…);\nINSERT INTO payments_v1 …" }
}
→ 7 of 7 columns mapped on layers 2–3 · no PAN field exists to map into · 0 AI tokens
  • The finance pack maps masked card data only. That is stated in the template source and enforced by the schema: there is no PAN field, so there is no mapping target for one.
  • payments_v1 is high-risk, so every mapping response carries requires_hitl: true. The flag is advisory in v1 — it tells your importer to gate; it does not block the commit server-side.
  • The sql emit writes a CREATE TABLE IF NOT EXISTS plus one INSERT INTO per row, keyed on the template id, and round-trips back through the SQL parser — so a dump you emit is a file you can re-import.
  • xlsm is refused on this path with xlsm_requires_template: macro output needs a source workbook to take macros from, and a file merely named .xlsm is the format/extension mismatch Excel refuses.

Where the work lands

Which layer resolves this file

LayerWhat it does hereAuto-accepts atCost
1 · statisticsThe processor’s exact header row, after ~20 unanimous confirmations≥100 @ 95% · ≥20 @ 100%Free · deterministic
2 · heuristic“last 4”, “card brand”, “currency”, “reference” — shipped hints in five languages≥ 0.85Free · deterministic
3 · fuzzy“amt” → amount, “ccy” → currency, “txn_ref” → processor_ref≥ 0.80Free · pure compute
4 · semanticA processor-specific label with no shared vocabulary≥ 0.78Cheap, cached · off without an embedding key
5 · aiOne batched call over the leftovers, constrained to unclaimed fieldsModel pick, constrained to the unclaimed column setMetered · the only paid layer

Layers run in strict cost order and short-circuit — the first layer that resolves a column claims the target field and no later, dearer layer sees it. Layers 4 and 5 are config-gated (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

payments_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 limit · The 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 subscription; you top up a prepaid wallet from $10 and it draws down.

Rate card · AI 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.

Mechanism · resolveRunPhi() 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

The payments_v1 template maps masked card data only — brand and the last four digits — and declares no field a full PAN could map to, so a PAN column in your source is reported as unmapped rather than carried through. Your own PCI scope depends on your whole environment; what we can say is that this template is built so cardholder data has nowhere to land.
No. AdaptivMapr normalises the file into your schema, validates it and delivers it. Matching settlements against ledger entries, handling fees and chargebacks, and deciding what an unmatched line means is reconciliation logic that belongs in your finance system. This removes the part where every processor has a different CSV.
It fails validation with the row index and the field named, rather than being accepted as a new category. That is deliberate: an unrecognised settlement state silently entering a ledger is worse than a rejected row. Map it explicitly, or extend your own schema with the values you actually use.
Yes. Destination connectors cover BigQuery (tabledata.insertAll), Snowflake (SQL Statement API v2 with key-pair JWT) and Databricks (SQL Statement API), plus sql_write over HTTP, Supabase via PostgREST — the only destination supporting upsert — object storage, and the SaaS three. Writes batch at 500 rows and are not transactional across batches, so check failed_batches.

Ready when you are

Stop hand-mapping this file. Map it once.

Start with a $10 prepaid wallet. In schema-only mode only headers and up to three clamped sample rows ever leave you.

$10 minimum to start · pay only for what you map · PHI under BAA coverage