Docs · Quickstart
Your first import, in five calls.
POST a file, let the six-layer cascade propose mappings, confirm them, and commit. Schema-only mode keeps raw records on your side; full-data routes the one AI call in-region under a BAA. Every map draws down a prepaid token wallet.
The whole flow
Five calls, start to finish
Each step below is one of these. The pill is the scope your key must carry — mint it with commit, or steps 4 and 5 come back 403.
- GET
/v1/templatesConfirm the key works and pick a target template.read - POST
/v1/uploadsParse the file. Returns an upload_id and the detected columns.transform - POST
/v1/uploads/:id/matchRun the cascade against the template you picked.read - PATCH
/v1/uploads/:id/mappingsConfirm the proposals you trust; correct the rest.commit - POST
/v1/uploads/:id/commitValidate every row and hand back the mapped result.commit
Everything below is these five calls with their bodies spelled out. If one of them refuses, the error names itself: the error reference lists every code worth branching on, and troubleshooting covers the failure modes that look like bugs and are not.
Step 1
Get an API key
Mint a key in the dashboard after you top up a prepaid token wallet ($10 minimum, shared across the phi-cloud suite). Keys are HMAC-signed and self-contained — there is no shared session store — and revocation is enforced by a server-side check on every request that fails closed. Pass the key as a bearer token in the Authorization header on every call.
Ask for the right scopes at mint. A key created without an explicit scope list gets read, transform and validate only. Steps 4 and 5 below need commit; without it they return 403 insufficient_scope, and the body names the scope that was missing in required_scope. A read-only listing call is the quickest way to prove the key works:
curl https://api.adaptivmapr.com/v1/templates \
-H "Authorization: Bearer $ADAPTIVMAPR_API_KEY"33 pre-built templates ship in the catalogue — 10 healthcare (FHIR-aware) plus Core, CRM, E-commerce, Finance & Payments, HR & People and Evidence. Pick the one whose shape matches your data, register your own under /v1/schemas, or browse the catalogue.
Step 2
POST your file
Send the file to POST /v1/uploads as multipart under the field name file. The parser accepts CSV, TSV, XLSX and XLSM, JSON, XML and Parquet, plus the tables inside .docx and .pptx; header_row and sheet_name are the two optional form fields when the defaults guess wrong.
The target template is not chosen here. The upload call only parses — you name the template on the match call in step 3, which means you can inspect the detected columns first and pick accordingly.
curl -X POST https://api.adaptivmapr.com/v1/uploads \
-H "Authorization: Bearer $ADAPTIVMAPR_API_KEY" \
-F "file=@roster.csv"
# when the sheet opens with title rows, or the workbook has several tabs:
# -F "header_row=3" -F "sheet_name=Roster"{
"upload_id": "upl_8f3a92c1",
"filename": "roster.csv",
"format": "csv",
"detected_columns": ["Vorname", "Nachname", "Geb", "E-Mail"],
"row_count": 1244,
"sample_rows": [ /* ≤3 rows, ≤80 chars per cell */ ],
"warnings": [],
"expires_at": "2026-09-03T09:14:22.000Z"
}Form fields
| Field | Type | What it does | |
|---|---|---|---|
file | file (multipart) | required | The file itself, under the field name file. Missing or not a file → 400 file_missing; over the 10 MiB cap → 413 file_too_large, with max_bytes in the body. |
header_row | integer | default 0 | Which row holds the headers. Raise it when a sheet opens with a title block or metadata rows. |
sheet_name | string | optional | Which worksheet to parse. Defaults to the first one in the workbook. |
multipart/form-data. Let your HTTP client set the Content-Type — a hand-written boundary is the most common reason this call 400s.
Prefer not to send a file at all? POST /v1/match takes just the headers plus ≤3 sample rows (≤80 characters each) and is stateless — that is all that leaves your environment, and it needs no key. Add table_name (the sheet or table the headers came from) when you call it with a key: the mapping ranker reads it as context.
Step 3
The cascade proposes mappings
Run the match against your upload_id, naming the template in target_schema.schema_id. Six layers fire cheapest-first — statistics → heuristic → fuzzy → semantic → LLM — and the moment a layer auto-accepts a column, the layers below it never run. Keep mode on "schema-only" to keep raw records on your side; "full-data" needs an active PHI entitlement, and without one the call returns 402 phi_gateway_required.
POST /v1/uploads/upl_8f3a92c1/match
{ "target_schema": { "schema_id": "patient_demographics_v1" },
"mode": "schema-only",
"use_ai": true }Request body
| Field | Type | What it does | |
|---|---|---|---|
target_schema.schema_id | string | required | A plain template id — patient_demographics_v1. There is no sch_ prefix and nothing to look up first. Unknown → 404 template_unknown; absent → 400 schema_id_required. |
mode | "schema-only" | "full-data" | default schema-only | full-data needs an active PHI entitlement; without one you get 402 phi_gateway_required. |
use_ai | boolean | optional | Set false to stop the cascade at layer 4. Columns that would have reached the metered call come back unmapped instead of billed. |
phi_mode | boolean | workspace default | Per-run routing override, falling back to the workspace setting, which defaults to off. PHI routing adds 20% and needs an accepted BAA, or you get 403 agreement_required. |
The response is one proposal per detected column, each tagged with the source layer that produced it — statistics · heuristic · fuzzy · semantic · ai · unmapped — plus a confidence, the reasoning, the unmapped list, and the auto_accept_threshold rules the statistics layer applied.
{
"upload_id": "upl_8f3a92c1",
"template_id": "patient_demographics_v1",
"mode": "schema-only",
"matches": [
{ "source_col": "Vorname",
"target_field": "first_name",
"confidence": 1.0,
"source": "heuristic",
"reasoning": "matched DE hint 'vorname'" }
],
"unmapped": ["Geb"],
"auto_accept_threshold": [ { "minN": 100, "minRatio": 0.95 },
{ "minN": 20, "minRatio": 1.0 } ],
"cascade_layers": ["statistics","heuristic","fuzzy","ranker","semantic","ai"]
}Step 4
Confirm or adjust
PATCH /v1/uploads/:id/mappings takes an array of {source_col, target_field, user_confirmed} overrides. Confirm the proposals you trust and correct the rest; corrections feed the statistics layer, so the same header resolves without AI next time — for this workspace only.
curl -X PATCH https://api.adaptivmapr.com/v1/uploads/upl_8f3a92c1/mappings \
-H "Authorization: Bearer $ADAPTIVMAPR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{ "source_col": "Geb", "target_field": "date_of_birth", "user_confirmed": true }]'One override
| Field | Type | What it does | |
|---|---|---|---|
source_col | string | required | A column from detected_columns, exactly as the parser read it. A name that is not in the upload is ignored rather than erroring. |
target_field | string | null | required | The field to map it onto, or null to leave the column unmapped on purpose. |
user_confirmed | boolean | default false | Only a confirmed override teaches the statistics layer. Sending a correction without it changes this run and nothing after it. |
The body is an ARRAY of these — send every column you want to change in one call, not one request per column.
For a medium- or high-risk template — patient_demographics_v1, lab_results_v1, claims_line_items_v1, payments_v1, employees_v1 and the rest — the response sets requires_hitl: true and hitl_status: "pending_review" so you can gate your own commit workflow behind a human review. The flag is advisory by default — the commit still goes through. Turn MAPR_HITL_ENFORCE on and it stops being advisory: the commit is refused with 428 hitl_required until you send hitl_approved: true.
{
"upload_id": "upl_8f3a92c1",
"mappings": [ /* ... */ ],
"requires_hitl": true,
"hitl_status": "pending_review"
}Step 5
Commit and use the rows
POST /v1/uploads/:id/commit validates every row against the template’s field validators and returns the mapped, validated rows inline (≤10k rows). Pass skip_invalid_rows to drop failures. Three delivery targets combine: inline rows, a webhook object ({url, secret}) that streams batches of 500 signed with an X-Mapr-Signature HMAC-SHA256 header — required above 10k rows — and a database object naming a destination connector.
output selects the shape: rows (the default), fhir, or a serialized file (csv, tsv, xml, sql, json, xlsx, parquet). The commit metadata always survives — the file rides inside the JSON envelope rather than replacing it.
curl -X POST https://api.adaptivmapr.com/v1/uploads/upl_8f3a92c1/commit \
-H "Authorization: Bearer $ADAPTIVMAPR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "skip_invalid_rows": true }'{
"committed": true,
"upload_id": "upl_8f3a92c1",
"template_id": "patient_demographics_v1",
"accepted": 1238,
"skipped": 6,
"mapping_fingerprint": "b91c…",
"delivery": "inline",
"delivery_mode": "inline",
"rows": [ /* the validated rows */ ]
}Request body
| Field | Type | What it does | |
|---|---|---|---|
skip_invalid_rows | boolean | default false | Drop failing rows and report them in skipped. Without it, one bad row fails the whole commit with 422 validation_failed. |
output | "rows" | "fhir" | file format | default rows | csv, tsv, xml, sql, json, xlsx, parquet. Anything else → 400 invalid_output. |
webhook | { url, secret } | optional | Signed batches of 500 to your endpoint. Required above 10 000 accepted rows — inline over that returns 413 inline_too_large. |
database | { connector_id, table?, on_conflict?, dry_run? } | optional | Write straight into a saved destination connector. Credentials come from the connector, never from this body. |
Every field is optional — an empty body commits the confirmed mapping as inline rows.
Every commit is hashed and written to the append-only audit trail with the mapping fingerprint and the accepted/skipped counts, so you can reconstruct exactly which rows landed from which file. The whole confirmed mapping is cached as a layout at the same moment, so the next file with this header row can be re-mapped with POST /v1/layouts/lookup and no AI at all.
Next
Keep going — put it in production.
The reference covers every /v1 route and its scope, the error codes worth handling, PHI routing and the BAA gate, connectors and signed webhooks, and the MCP server for Cursor and Claude Desktop.
Prepaid token wallet · schema-only data-minimization mode · no free tier