Capability · Convert
A scan, a photo, a recording — all of it as rows.
A scan, a photograph, a recording, a web page. If a person could read the numbers out of it, you can get them as rows.
- Input kinds
- 9
- Routing, on every response
- Named
The job
It is not a spreadsheet, and it still has to land in your system.
What changes
What you get
Not a demo. The thing that runs every day.
Structured
Spreadsheets never egress
CSV, TSV, JSON, XLSX, XML, SQL dumps, Word and PowerPoint tables, Parquet and a saved SQL query are parsed inside the Worker. Nothing in that family leaves.
HowThe structured family is parsed by lib/parser.ts in-process and reported as routing: "inline". An input.connector_id pointing at a saved sql_http connector lands here too — its result set is just another row grid.
Images
One vision call, straight to rows
A photographed form or a screenshot goes to a vision model in a single structured call — image in, mapped records out. No OCR round-trip in between.
HowMAPR_VISION_MODEL (Gemma-4) is PHI-eligible on phi-cloud, so a PHI-routed image never reaches a general-data host and the response reports routing: "inline".
PDFs
Layout OCR, and its tables feed the cascade
A PDF is read by a layout-aware extractor that returns real table grids, not a wall of text. Those grids go straight into the mapping cascade; only prose falls back to a model.
HowMAPR_OCR_MODEL=layout is Azure Document Intelligence and is PHI-eligible, so a PHI-routed PDF stays inside the BAA boundary. lib/doclingTables.ts scores the returned grids against your target and hands the best one to the cascade.
Audio & web
General-data only, stated up front
Transcription and headless web ETL run on upstreams that refuse PHI traffic. That is a real limit, so we report it on the response rather than hiding it.
HowThe transcription and ETL upstreams reject X-PHI, so audio, HTML and URL inputs always come back as routing: "general". The same is true of the sovereign docling OCR tier — it never leaves our own infrastructure, and is general-data by construction.
Receipts
Every response says where the bytes went
You never have to reason about our routing table from the outside. The answer is a field on the response and a header on the wire.
Howrouting in the JSON envelope and x-mapr-routing on every non-JSON output: inline means nothing reached a general-data host, general means raw bytes did.
Schema
Four ways to say what you want out
Point at a catalog template, declare fields inline, describe the shape in English, or let the extractor infer it from the document itself.
Howschema: { ref: "invoices_v1" }, { fields: [...] }, { from_prompt: "..." } or { infer: true } — resolved by lib/schema/resolve.ts, and the response reports which of the three sources was used.
How it works
What each input costs you in exposure
Not every source is a file with headers. Convert extracts structured records from anything — a scanned intake form, a PDF invoice, a recording, a web page — and shapes them onto your schema through the same cascade. Where the bytes go depends on the document type, and that is not something you should have to guess: every response carries a routing field naming exactly what left.
- 01
Classify the input
The declared format decides the pipeline, and therefore the exposure. That decision happens before a single byte moves, which is why it can be reported to you rather than discovered afterwards.
- 02
Extract
Structured formats are parsed in the Worker. An image goes to one vision call; a PDF to layout OCR that returns real table grids; audio and web pages to their own upstreams.
- 03
Shape onto your schema
An extracted grid is handed to the same six-layer cascade as any spreadsheet — only prose with no table falls back to a model to be structured.
- 04
Report where it went
routingon the JSON envelope andx-mapr-routingon every non-JSON output, alongside the row count and the per-row validation errors.
| Input | How it is read | Where the bytes go | routing |
|---|---|---|---|
| CSV · TSV · JSON · XLSX · XML · SQL · DOCX · PPTX · Parquet | Parsed in the Worker | Nowhere | inline |
| PNG · JPEG · WebP · GIF | Vision model, one structured call | phi-cloud — PHI-eligible | inline |
| Layout OCR (Azure Document Intelligence) | phi-cloud — PHI-eligible | inline | |
| WAV · MP3 · M4A · OGG · FLAC | Transcription, then shaped | phi-cloud — general-data upstream | general |
| HTML · a URL | Headless ETL, then shaped | phi-cloud — general-data upstream | general |
inline only when the run is PHI-routed AND the tier that served it was a PHI tier — otherwise the response honestly says general. Unstructured input is full-data by nature, so it needs the PHI entitlement; a request that asks to keep it on standard routing is refused with 400 phi_required_for_full_data rather than quietly downgraded.Try it
A PDF invoice into your invoice schema
Name the input and the schema. The extractor reads the document, the cascade maps its table onto your fields, and the envelope tells you the row count, the failures, and the routing.
curl https://api.adaptivmapr.com/v1/convert \
-H "Authorization: Bearer $MAPR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": { "format": "pdf", "data_base64": "JVBERi0xLjcK…" },
"schema": { "ref": "invoices_v1" },
"mode": "full-data",
"phi_mode": true
}'{
"schema_id": "invoices_v1",
"source": "registry",
"routing": "inline",
"row_count": 12,
"errors": [
{ "row_index": 7, "field": "currency", "code": "required", "message": "currency is required" }
],
"data": [
{ "invoice_number": "INV-2043", "customer_id": "C-118",
"amount_due": "1240.00", "currency": "EUR",
"due_date": "2026-06-13", "status": "unpaid" }
]
}- Unstructured input is full-data by nature, so it needs the PHI entitlement: without it the endpoint answers
402 phi_gateway_requiredrather than reading the document anyway. POST /v1/gatewayis this same pipeline with a destination attached — the mapped rows are written into your table and you get a delivery report back instead of the data.- Convert needs a configured LLM key. Where that key is unset the endpoint reports
503instead of degrading into a worse answer.
The surface
Every route this page actually has.
Convert reads; gateway reads and writes. They share one compute core, so the mapping, the data-mode gate and the validators are byte-identical — and they stay separate routes so a read can never accidentally become a write.
- POST
/v1/convertAny input, any output format. 60 requests a minute per workspace.transform scope - POST
/v1/gatewayThe same pipeline with a destination attached — you get a delivery report back instead of the data.commit scope - POST
/v1/transformThe tabular fast path: a file or pasted text straight to an output format, capped at 10 000 rows inline.transform scope - POST
/v1/me/convertThe dashboard twin — what the Workbench calls when you drop a document rather than a spreadsheet.dashboard only - GET
/v1/usagePer-period row counts and per-cascade-layer hit counts, so you can see how much of your spend actually reached a model.read scope
Limits & failure modes
What it refuses to do — and the code it says it with.
The interesting failures here are all about exposure. Convert would rather refuse than read a document down a path you did not agree to.
402 phi_gateway_requiredUnstructured input without the PHI entitlement on the workspace.
Images, PDFs, audio and web pages are full-data by nature — there is no clamped version of a scan — so the endpoint refuses rather than reading it anyway.
400 phi_required_for_full_dataA caller asks to keep unstructured input on standard routing.
Refused rather than quietly downgraded: misreporting the routing would misreport the price too, since PHI routing carries the +20%.
403 phi_route_blockedThe configured upstream host is not on the BAA-covered allowlist.
MAPR_PHI_ALLOWED_HOSTS fails CLOSED: with no allowlist, no full-data PHI traffic leaves at all, and the health endpoint reports the component down.
503 extraction_unavailableNo LLM key is configured, or the extractor upstream is unreachable.
Reported as unavailable rather than degraded into a worse answer from a weaker path you did not choose.
400 legacy_xls_unsupportedA legacy .xls (BIFF) workbook.
Re-save as .xlsx and retry. .xlsb is refused by name for the same reason — the modern formats are ordinary OOXML zips we can read exactly.
routing: "general"Audio, HTML or a URL — always. And the sovereign docling OCR tier.
Not an error, but a real limit: those upstreams reject X-PHI, so raw bytes did reach a general-data host. We put it on the response rather than in a footnote.
What it costs
One prepaid wallet, drawn down per call.
No free tier. Top up from $10 — the balance is shared across the phi-cloud suite — and every operation draws it down at the rate below. An optional $6/mo plan grants a credit that resets each billing cycle instead; overage falls back to the wallet.
Every convert
$0.001
The flat per-map fee, as with any other map. Structured input that never leaves the Worker still draws it.
Extraction & shaping
cost × 2
The vision, OCR, transcription or ETL tokens actually consumed, at provider cost × 2 — or × 0.5 when you bring your own LLM key.
PHI-routed document
+20%
Applied to the whole charge when the run really was PHI-routed, in-region under a BAA. Standard runs pay no uplift.
A PHI/enterprise-routed run multiplies the whole charge by 1.2 (+20%), flat fee included — and only when the run genuinely got that routing. PHI stays locked until the workspace accepts the BAA in Settings → Security & Data. Full pricing
Questions
The ones asked before signing.
What it costs, what leaves your network, and the claims we will not make.
How is convert billed against schema-only mapping?
Can I convert PHI documents?
What powers the Workbench “drop a doc” flow?
Do I have to declare a schema?
Keep reading
The rest of the same engine.
One key, from a messy file to your schema.
Top up a $10 prepaid wallet and start mapping. In schema-only mode only your headers and three clamped rows ever leave you.