AdaptivMapr

Solution · Core, CRM & E-commerce

Your customer's export, onboarded today.

Stop asking customers to reshape their file. Take whatever they send and onboard it the same day they send it.

On the second upload
One click
Templates, or bring your own
33
The pack

Core · CRM · E-commerce

templates
13templates
gate on review
0gate on review
field validators
5field validators
hint languages
5hint languages
users_v1transactions_v1addresses_v1leads_v1contacts_v1+8 more

The job

Onboarding stalls on the first file.

Every customer’s export looks different, so either an engineer writes a bespoke importer per account, or support asks the customer to rearrange their columns and wait. Both happen at exactly the moment the customer is deciding whether this was a good idea.

What changes

They send the file as it is. It maps to your schema, they confirm anything uncertain, and the mapping is remembered — so their next upload needs nobody at all.

What actually arrives

Every source exports it differently.

Every SaaS has to onboard customer data, and every customer’s export looks different. Building a bespoke importer per account — or asking the customer to reshape their file — is friction at exactly the wrong moment. Thirteen low-risk templates cover the common objects, and a confirmed layout makes the next import of that shape a lookup.

Four shapes cover most self-serve onboarding. They arrive at the worst possible moment — the first day of a new account — which is why the mapping has to be someone else’s problem.

The competitor export

CSV, whatever the previous tool emitted

Column names from another product’s domain model, an id column that is not your id, a Notes field carrying three concepts, and a trailing summary row that is not data.

The spreadsheet the ops team maintains

XLSX, several sheets, merged header cells

The real header row three rows down under a title; a colour code that carries meaning; blank spacer columns; one sheet per region with slightly different columns.

A product catalogue

CSV or XLSX, one row per SKU

EAN, GTIN and Barcode as three names for one field; prices with a comma decimal; category as a breadcrumb string; stock as a boolean in one file and a count in the next.

A CRM dump

CSV export from the CRM’s own report builder

Contact and account columns flattened into one row; the owner as an email in one export and a display name in another; stage names customised per tenant.

13 templates

Core · CRM · E-commerce — every field carries DE / FR / IT / EN / ES hints.

13 low-risk templates

Nothing here flags for review, so onboarding imports commit straight through.

5 field validators

gtin, email, phone, url, number_range

  • Headers + ≤3 rows, 80 chars each
  • Layers 1–3 need no model
  • requires_hitl on medium + high
  • PHI pinned in-region under a BAA
  • Per-workspace, never cross-tenant

How it works

Four calls, and the file is in your schema.

Upload, cascade, confirm, commit. The deterministic layers do most of the work before anything metered runs, and nothing but headers and a few clamped sample rows leaves your system on the way.

  1. 1Step 1

    Take the file as it comes

    A user list, a CRM contact dump, a product catalog, an orders CSV — whatever the customer exported, uploaded as-is. No pre-formatting, no column renaming, no template picked by the customer.

    POST /v1/uploadscsv · xlsx · json · sql
  2. 2Step 2

    The cascade maps it

    Statistics, heuristic and fuzzy resolve the common business objects against the Core, CRM and E-commerce packs. Artikelnummer, référence and codice articolo all reach sku without a model call — the hints are on the field, and the heuristic layer compares against them at zero cost.

    corecrmecommerce
  3. 3Step 3

    Validate the formats the template defines

    gtin on catalog items runs the GS1 checksum, not a length check; email, phone and url are format-checked on contacts, leads and accounts. A bad barcode fails with gtin_checksum before it reaches your database.

    gtinemailphoneurl
  4. 4Step 4

    Commit — and make the next one a lookup

    Commit writes inline, to a signed webhook, or into a saved database connector. It also records the confirmed layout against a fingerprint of the normalized header row, so the same shape next month can skip mapping entirely.

    POST /v1/layouts/lookupPOST /v1/layouts/drift

Field level

One template, printed in full.

One of the thirteen, printed field by field. Every row below is a field object the catalogue ships, with the validator ids that run on it and the header vocabulary the free heuristic layer already recognises — which is why a German or Italian catalogue maps without anyone touching a mapping UI.

products_v1low9 fields · 3 required · 1 validated
FieldTypeRequiredValidatorsHeader vocabulary it already knows
skustringrequired—sku · artikelnummer · référence · codice articolo +1
namestringrequired—name · nom · nome · nombre
descriptionstring———
pricenumberrequired—preis · prix · prezzo · precio
currencystring——währung · devise · valuta · moneda
gtinstring—gtingtin · ean · barcode
categorystring——kategorie · catégorie · categoria · categoría
weight_gnumber——gewicht · poids · peso
in_stockboolean——vorrätig · en stock · disponibile · disponible
Every row is a field object from GET /v1/templates/products_v1 — not a description of one. The hint lists are what the heuristic layer compares a header against after normalize() strips accents, punctuation and whitespace, which is why adding a hint is the highest-leverage change in the whole engine: it costs nothing to run and removes a model call.

Why AdaptivMapr

Built for the shape of regulated data.

What the business packs pack gives you that a generic importer does not — and, under each card, the mechanism that does it.

Thirteen templates, all low-risk

Core covers users, transactions and addresses; CRM covers leads, contacts, accounts, opportunities and activities; E-commerce covers orders, products, customers, inventory and returns. None of them flags for review, so onboarding commits straight through.

HowEvery field carries DE / FR / IT / EN / ES hints — the same multilingual layer the regulated packs use — so a European customer’s export maps without anyone touching a mapping UI.

The second import of a shape is a lookup

A confirmed mapping is cached whole, keyed by a sha256 fingerprint of the normalized header row. When that shape arrives again your importer can offer one-click reuse and skip mapping — and still be billed only the flat per-map fee.

HowPOST /v1/layouts/lookup reads it, /v1/layouts/record writes it, and /v1/layouts/drift diffs a new field set against the newest confirmed layout for that template — added / removed / common, deterministic, no model. Workspace-scoped, never shared.

Recurring feeds pull themselves

Register a scheduled ingest source once and let it pull and map on a cadence. Delivery is a signed, queued webhook with a dead-letter queue and admin replay — a failed delivery is visible and re-sendable, not lost.

HowConnector secrets are KEK-encrypted at rest. Webhook delivery runs on a Cloudflare Queue with a DLQ journal; five cron triggers drive activation, audit cleanup, audit digest, connector sync and migration checks.

Drive it from your product, or from an agent

The whole flow is a small REST surface under /v1, and the same catalogue is exposed over MCP so an agent can list templates and match headers directly. Keys are self-contained and verify without a database lookup.

HowAPI keys are HMAC-signed and carry their own tenant_id — authentication needs no lookup. GET /v1/templates and GET /v1/packs are public and static: the catalogue on this page is the catalogue the API serves.

The frame

What applies here, and what we actually do about it.

Each frame below is paired with a mechanism, not an adjective. Where we hold nothing, the row says so — a compliance page that overstates is worse than one that is short.

GDPR / nFADP — your customers’ customers

A user list or a CRM dump is personal data, and it belongs to your customer. You are a processor for it, and so is anything you hand it to.

Our posture · Schema-only sends headers plus up to three sample rows clamped to 80 characters — enforced by one chokepoint at the HTTP edge — so an onboarding import does not put your customer’s contact list through a model. A DPA is provided on request.

Tenant isolation

One customer’s learned mappings must never surface in another customer’s import.

Our posture · Learned mapping statistics and cached layouts are workspace-scoped. Uploads live in Cloudflare KV under the workspace retention window (24h by default, up to 30d) with explicit tenant scoping; the dashboard plane runs under Supabase row-level security. Nothing is pooled across tenants, and there is no cross-tenant catalogue of “what other customers called this column”.

Risk, even where it is low

A low-risk template is a claim, and a claim needs a mechanism behind it.

Our posture · All thirteen business templates are rated low, so PATCH /mappings returns requires_hitl: false and an onboarding import commits straight through. The rating lives on the template and drives the flag in code — if one of these ever becomes medium, every caller starts seeing the gate in the same deploy.

Operational integrity

A failed delivery that disappears is worse than one that errors.

Our posture · Webhook delivery runs on a Cloudflare Queue with a dead-letter queue and admin replay, connector secrets are KEK-encrypted at rest, and commits are written to the audit trail with the mapping fingerprint.

What we do not claim: SOC 2 is in progress, there is no free tier, and AdaptivMapr is not a drop-in replacement for a hosted onboarding UI such as Flatfile. It has no end-customer importer widget. It is the engine you put underneath the import experience you have already designed.

Risk & review

The pack, printed.

Every template this vertical ships, with the risk level that decides whether a commit gates on human review.

Template idRiskCommit gateValidators
users_v1lowrequires_hitl: falseemail
transactions_v1lowrequires_hitl: false—
addresses_v1lowrequires_hitl: false—
leads_v1lowrequires_hitl: falseemail, phone
contacts_v1lowrequires_hitl: falseemail, phone
opportunities_v1lowrequires_hitl: falsenumber_range, email
accounts_v1lowrequires_hitl: falseurl
activities_v1lowrequires_hitl: false—
orders_v1lowrequires_hitl: false—
products_v1lowrequires_hitl: falsegtin
customers_v1lowrequires_hitl: falseemail, phone
inventory_v1lowrequires_hitl: false—
returns_v1lowrequires_hitl: false—
Read from the live template catalogue — the same ids, risk levels and validator ids that GET /v1/templates returns. Nothing on this table is typed by hand.

The gate is a property of the template.

There is no setting for it and no per-id list to maintain. A template rated medium or high makes PATCH /mappings return requires_hitl: true and hitl_status: "pending_review" — on every call, for every workspace, derived in one line of the route from the risk field. AdaptivMapr sets the flag; your workflow owns the queue. A native review queue is on the roadmap, not in v1.

13 low, 0 flagged

In this vertical, out of 13 templates.

13 flagged of 33

Across all 7 packs the engine serves on GET /v1/templates.

PATCH /v1/uploads/:id/mappings
[
  { "source_col": "Sku",
    "target_field": "sku",
    "user_confirmed": true }
]
response · users_v1
{
  "upload_id": "upl_7a41c2…",
  "mappings": [ … ],
  "requires_hitl": false,
  "hitl_status": "not_required"
}
the body is an ARRAY of { source_col, target_field, user_confirmed } · 409 no_template if /match has not run on this upload yet

In code

A real call, end to end.

A customer’s product catalog against products_v1 — mapped on the free layers, GTIN checksummed at validate, then the confirmed layout cached so the next monthly file is a lookup instead of a map.

  • POST/v1/uploadsparse the file, return its headers + ≤3 clamped sample rows
  • POST/v1/uploads/:id/matchrun the six-layer cascade against one template
  • PATCH/v1/uploads/:id/mappingsrecord confirmations; returns requires_hitl
  • POST/v1/uploads/:id/validaterun the field validators over every row, indexed
  • POST/v1/uploads/:id/commitemit and deliver — inline, webhook or DB connector

Authentication is one header. Keys are HMAC-signed and carry their own tenant_id, so verifying one needs no database lookup — and a key can be scoped so the service that reads mappings is not the one allowed to commit them.

curl
# 1 · upload the customer's file, unmodified
curl -s https://api.adaptivmapr.com/v1/uploads \
  -H "Authorization: Bearer $MAPR_KEY" \
  -F file=@artikelstamm.csv

# 2 · map to the e-commerce catalog template
curl -s https://api.adaptivmapr.com/v1/uploads/$ID/match \
  -H "Authorization: Bearer $MAPR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target_schema":{"schema_id":"products_v1"},
       "mode":"schema-only"}'

# 3 · next month, reuse the layout instead of mapping
curl -s https://api.adaptivmapr.com/v1/layouts/lookup \
  -H "Authorization: Bearer $MAPR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template_id":"products_v1",
       "headers":["Artikelnummer","Name","Preis","EAN","Kategorie"]}'
response
{
  "template_id": "products_v1",
  "mode": "schema-only",
  "matches": [
    { "source_col": "Artikelnummer", "target_field": "sku",      "confidence": 1, "source": "heuristic" },
    { "source_col": "Name",          "target_field": "name",     "confidence": 1, "source": "heuristic" },
    { "source_col": "Preis",         "target_field": "price",    "confidence": 1, "source": "heuristic" },
    { "source_col": "EAN",           "target_field": "gtin",     "confidence": 1, "source": "heuristic" },
    { "source_col": "Kategorie",     "target_field": "category", "confidence": 1, "source": "heuristic" }
  ],
  "unmapped": [],
  "cascade_layers": ["statistics","heuristic","fuzzy","ranker","semantic","ai"]
}
schema-only · headers + ≤3 rows clamped to 80 chars left your system · all templates here are low-risk, so commit is not gated

Rollout

From one file to a feed that runs itself.

Four phases, none of which requires the previous one to be finished. Most teams stop after the third and only wire the fourth when a customer starts sending the same file every month.

  1. 1

    Point it at your worst onboarding file

    Not your cleanest one — the export from a customer that took three days last quarter. Run it in schema-only mode against a business template and read which layer resolved each column.

    POST /v1/uploadscsv · xlsx · json · sql
  2. 2

    Put it behind your own import screen

    The whole flow is four REST calls, so the mapping UI stays yours: your copy, your confidence thresholds, your review step. The same catalogue is exposed over MCP if you would rather an agent drive it.

    REST /v1MCP
  3. 3

    Turn confirmations into a cache

    Record the confirmed layout on commit and look it up on the next file. The second import of a shape is a lookup rather than a map, and a customer whose export changes shape shows up as a deterministic drift diff instead of a support ticket.

    /v1/layouts/record/v1/layouts/lookup/v1/layouts/drift
  4. 4

    Let the recurring feeds run themselves

    Register a connector for a customer who sends the same file every month and let it pull and map on a cadence, delivering through a signed, queued webhook with a dead-letter queue and admin replay.

    connectorssigned webhookDLQ replay

FAQ

The questions that decide it.

What do the business packs cover?
Three packs, thirteen templates. Core (3): users_v1, transactions_v1, addresses_v1. CRM (5): leads_v1, contacts_v1, accounts_v1, opportunities_v1, activities_v1. E-commerce (5): orders_v1, products_v1, customers_v1, inventory_v1, returns_v1. All low-risk, and every field carries DE/FR/IT/EN/ES hints so a customer’s export maps regardless of their header language.
Why are onboarding imports fast and cheap here?
Business objects have common column names, so the three free deterministic layers resolve most of them: statistics (learned from your confirmations), heuristic (normalized comparison against the field name, label and its hints) and fuzzy (token-set plus Levenshtein, auto-accepting at 0.80). A column that resolves there never reaches the metered model layer. There is no free tier — every map still draws the small flat per-map fee — but a low-risk business file is close to that floor.
How does layout reuse work for recurring imports?
When a mapping is confirmed, the whole layout is cached against a sha256 fingerprint of the normalized header row. The next time that shape arrives, POST /v1/layouts/lookup returns the stored mapping so your importer can offer one-click reuse and skip mapping entirely. POST /v1/layouts/drift uses the same fingerprints to detect schema drift: a new field set for a known template comes back as drift with an added / removed / common diff, or stable, or first_seen — deterministic, no model. Layouts are workspace-scoped; nothing is shared between tenants.
Can I automate this without manual uploads?
Yes. Connectors register a scheduled ingest source with KEK-encrypted secrets and pull on a cadence, delivery runs through a queued, signed webhook with a dead-letter queue and admin replay, and the whole flow is available over the REST /v1 API and the MCP adapter for programmatic onboarding.
Is this a replacement for a hosted importer product?
No. AdaptivMapr is the mapping engine and its API — a six-layer cascade, a template catalogue, validators, layout reuse and delivery. It is not a drop-in replacement for a hosted onboarding UI, and it does not front a clinical integration engine. Teams use it as the mapping layer underneath their own import experience.
Can we run this with no AI in the loop at all?
Yes. The semantic layer needs an embeddings key and the LLM layer needs a phi-cloud key; both are config-gated and fail soft to OFF. With neither configured only statistics, heuristic and fuzzy run — which, for common business objects with multilingual hints on every field, resolves most columns anyway. Anything left over comes back in unmapped for your UI to ask about.
What happens when a mapping is wrong?
Every match carries a confidence and the layer it came from, so your import screen can show a weak pick rather than hiding it. An override in PATCH /v1/uploads/:id/mappings with user_confirmed: true teaches the statistics layer for your workspace, and a choice that differs from the suggestion records the original as a negative signal. Contests between columns are settled by layer rank then confidence — never by column order — so the same file maps the same way whichever order the columns arrive in.
What does high-volume onboarding cost?
There is no free tier, no seats and no contract. AdaptivMapr runs on a prepaid token wallet with a ~$10 minimum, shared across the phi-cloud suite. Every map draws a small flat fee — a few tokens — including a fully deterministic map and a layout-cache hit that uses no AI. A low-risk business file that resolves on the free layers sits close to that floor, and standard routing pays no PHI surcharge.

Map business packs data without shipping raw records.

Start on schema-only — headers and a few clamped sample rows, a few tokens per map. Turn on PHI routing when you need it: in-region, under a BAA you accept in the app.

Business data onboarding — Core, CRM and E-commerce packs — AdaptivMapr — AdaptivMapr