Platform
One engine. Any data in, your schema out.
A stateless, pure-compute mapping cascade that turns any CSV, Excel, JSON, or SQL into your schema — resolving most columns on free deterministic layers before any AI is touched.
The cascade
Five layers, cost-ordered — the engine stops the moment a column resolves.
Each header runs down a ladder from free and deterministic to metered AI. The instant a layer is confident, the cascade accepts and moves on — so most files are fully mapped before the paid layer is ever touched. That early exit is the single biggest cost lever in the system.
- Layer 1
Statistics
Auto-accept from confirmed history: a header maps when past confirmations for it agree at a production-tested ratio.
{minN:100, minRatio:0.95} · {minN:20, minRatio:1.00}free · deterministic
- Layer 2
Heuristic
normalize() strips accents, punctuation and whitespace, then compares the header against each field’s column, label and every hint (DE/FR/IT/EN/ES).
exact = 1.00 · substring = 0.85free · pure compute
- Layer 3
Fuzzy
Token-set ratio plus Levenshtein over the normalized strings — tolerates typos and token-order drift ("Frist Name", "name first").
FUZZY_AUTO_ACCEPT = 0.80free · pure compute
- Layer 4
Semantic
Embeddings cosine over the header against each field’s label + hints. Cached, and silently skipped when no embedding key is configured.
SEMANTIC_THRESHOLD = 0.78cheap · cached
- Layer 5
LLM
Every header still unresolved goes into ONE collision-aware batched call, constrained to your column set and told which fields are already claimed.
1 call per file · llmMatchHeadersBatch()metered
Contests are settled by quality, not column order: layers 1–3 all propose, the engine arbitrates once on (layer rank, confidence, column index), then runs layer 4 only for what is still unresolved. A target field, once assigned, cannot be claimed twice — you can’t emit two source columns into one field. How the cascade works →
- No raw records to an LLM
- HMAC self-contained API keys
- RLS tenant isolation
- Uploads expire from KV in 24 h
- In-region PHI routing under a BAA
Structural understanding
Real-world grids are messy. The engine reads them before it matches.
Before a single header is compared, a deterministic pass (lib/structure.ts) turns spreadsheets-as-humans-made-them into clean logical tables. No LLM, no configuration — just structure recovery.
Multi-row & grouped headers
Unit rows captured
Transposed sheets un-pivoted
Reshape: beyond renaming
When mapping isn’t enough, the engine reshapes — safely.
Some inputs need more than column renaming: a pivot, a split, a join across sheets. A router picks the cheapest strategy that works, and the model — when one is used at all — never sees your data.
direct
How · No program is authored at all — the mapping IS the transform.
plan
How · Re-run a plan and you get identical bytes back.
code
How · Every prompt carrying customer content is fenced; the generated program runs behind network isolation.
Across every generated path the boundary holds: the model is shown a skeleton — headers plus a clamped preview — and writes a transform it never gets to run against your full records. See how reshape works →
Two modes, one boundary
Schema-only, or full-data under a BAA — the boundary is one code path.
Both modes run the same in-process cascade. The only difference is what may leave you, and both are gated at a single clamp — not scattered across routes.
| Schema-only | Full-data | |
|---|---|---|
| What leaves you | Column headers + up to 3 sample rows, each clamped to ≤80 characters. Raw records stay home. | The same clamped preview for matching — plus, for the layer-5 call only, the cells that fell through to the LLM. |
| Where it runs | Entirely in-process. The deterministic cascade never phones out. | In-process cascade; the single layer-5 LLM call routes to a PHI-eligible, in-region provider under X-PHI + X-Region. |
| Compliance | Data-minimized — only clamped previews leave you, so a DPA often isn’t needed (provided on request). | Active PHI entitlement, plus a BAA accepted in-app. In-region, PHI-eligible model enforced at the gateway. |
| One clamp | clampForSchemaOnly() is the single edge chokepoint every route shares. | Same clamp for matching; the data boundary is one code path, not per-route promises. |
Schema-only is a data-minimization mode — only clamped previews leave you. Full-data is gated behind an active PHI entitlement and an accepted BAA; only the layer-5 LLM call routes to a PHI-eligible provider, in-region.
The API
Every surface is a REST route you can read.
No SDK required and no bespoke verbs: the engine is a dozen routes under /v1, each doing one thing. These are the paths as they exist in the codebase.
- POST
/v1/uploadsStage a CSV, Excel, JSON or SQL export. Returns an upload id; the bytes live in KV for 24 hours. - POST
/v1/uploads/{id}/matchRun the five-layer cascade over the file’s headers against a template. - POST
/v1/uploads/{id}/match/streamThe same run as Server-Sent Events — a frame per cascade layer.streams - PATCH
/v1/uploads/{id}/mappingsOverride a proposed mapping. Medium- and high-risk templates come back with requires_hitl. - POST
/v1/uploads/{id}/commitConfirm the mapping. Feeds layer 1 and records the layout fingerprint for one-click reuse. - POST
/v1/matchHeaders plus ≤3 clamped sample rows, no key required. Deterministic layers only — the metered layer is never reachable anonymously.public - POST
/v1/reshapePivot, split, join across sheets. The router picks direct, plan or code, and echoes which it chose. - POST
/v1/convertAny-to-any import: images, PDF, audio, HTML and URLs into structured rows. - POST
/v1/layouts/lookupReuse the last confirmed mapping for an identical header row — a fingerprint cache hit, no AI. - POST
/v1/layouts/driftDiff a new field set against the newest confirmed layout: stable, first_seen, or drift with an added/removed diff. - GET
/v1/templates33 templates across 7 packs, with their fields, multilingual hints and validators. - GET
/v1/usageMetered usage for the workspace; ?phi=1 adds token consumption and cost.
The public host is api.adaptivmapr.com. Dashboard-session routes live under /v1/me/* and are CSRF-gated. Full API reference →
For developers
One call, and the layer is in the answer.
Every match carries the layer that produced it and the confidence it produced it at. You can prove which columns cost nothing — and exactly which ones reached the metered layer.
- REST /v1 — uploads, match, mappings, commit, reshape, convert, layouts, templates, usage
- HMAC self-contained keys — a key verifies without a database lookup; revocation is a check layered on top
- SSE progress — /match/stream and /me/reshape/stream emit a frame per phase, then the same terminal JSON
- MCP — mapr.match_headers calls POST /v1/match, clamped to the schema-only contract at the edge
curl -s https://api.adaptivmapr.com/v1/match \
-H 'content-type: application/json' \
-d '{
"template_id": "lab_results_v1",
"headers": ["Patient-ID","LOINC","Wert","Einheit","Entnahme"],
"sample_rows": [["P-1042","2345-7","5.4","mmol/L","2026-03-11"]]
}'{
"template_id": "lab_results_v1",
"matches": [
{ "source_col": "Patient-ID", "target_field": "patient_id", "confidence": 1, "source": "heuristic" },
{ "source_col": "LOINC", "target_field": "loinc_code", "confidence": 0.85, "source": "heuristic" },
{ "source_col": "Wert", "target_field": "value", "confidence": 1, "source": "heuristic" },
{ "source_col": "Einheit", "target_field": "unit", "confidence": 1, "source": "heuristic" },
{ "source_col": "Entnahme", "target_field": "taken_at", "confidence": 1, "source": "heuristic" }
],
"auto_accept_threshold": [
{ "minN": 100, "minRatio": 0.95 },
{ "minN": 20, "minRatio": 1 }
],
"cascade_layers": ["statistics","heuristic","fuzzy","semantic","ai"],
"unmapped": []
}Built for regulated data
Compliance isn’t a mode — it’s the substrate.
The cascade is the product, but the deployed engine is a full stateful SaaS with the controls regulated teams have to answer for. These are wired in, not roadmap.
Hash-chained audit trail
How · mapping.commit carries review_approved and the attempt count.
24-hour upload TTL
How · lib/uploads.ts — KV write with a 24h TTL, mirrored to Supabase.
KEK-encrypted secrets
How · GET /v1/connectors/{id}/secret-meta returns metadata, never the secret.
Strict CSP, per-request nonce
How · middleware.ts mints x-nonce; every JSON-LD block on this page carries it.
Fail-closed PHI allowlist
How · MAPR_PHI_ALLOWED_HOSTS — /api/health reports the component down when unset.
HIPAA-ready, GDPR & nFADP posture
How · BAA + confidentiality terms are accepted in-app and recorded in tenant_agreements.
Ready when you are
One key unlocks the whole engine.
Schema-only mode runs the same cascade on your prepaid wallet — every map is a few tokens; only files that need the paid layer add AI token cost.