Use case · Finance & Payments
Load KYC profiles from a provider you did not choose.
Onboarding a KYC vendor, or migrating off one, means importing identity profiles with risk ratings attached. Map them to kyc_profiles_v1 — a high-risk template that comes back flagged for review every single time.
The job
What you are actually trying to get done
You are switching KYC providers, or absorbing a book of business, and the profiles come out in the outgoing vendor’s shape. The data is identity data with a risk rating attached — exactly the category that should not be loaded by a script nobody reviewed. The job is to map it once, validate the dates and identifiers, and have the review flag be a property of the data rather than a habit.
Where it lands
KYC profiles
kyc_profiles_v1 · risk: high
date_of_birth carries a date_range validator of 1900-01-01 → today, so an epoch-zero default or a year typed as 2206 fails rather than entering the file. risk_rating is an enum of low / medium / high — the vendor’s own five-band scale has to be mapped deliberately, not guessed.
Canonical columns
- subject_id
- legal_name
- date_of_birth
- national_id
- country
- risk_rating
- verified_at
7 canonical columns · 2 required · 2 validated
Step by step
The whole run, one call at a time
- 1
Upload the export
A JSON array of objects is parsed natively — the union of keys, in first-seen order, becomes the header row the cascade works from.POST /v1/uploads - 2
Map the camelCase
normalize()strips punctuation and case, solegalName→legal_nameandnationalIdentifier→national_idland on the free layers.dobis a shipped hint ondate_of_birth.POST /v1/uploads/:id/match - 3
Map the risk scale explicitly
riskBandmaps torisk_rating, but the vendor’s band vocabulary is not ours. The enum forces the decision into the open: values outsidelow/medium/highfail validation instead of arriving unlabelled.PATCH /v1/uploads/:id/mappings - 4
Validate identity fields
national_idagainst the template’s regex,date_of_birthagainst its range,verified_atas a date. Errors carry the row index and the field.POST /v1/uploads/:id/validate - 5
Review, then commit
High-risk, so the flag is on every response. Commit inline, to a signed webhook, or into a destination connector — the same commit can do more than one of those.requires_hitl: true
In code
JSON in, validated profiles out
POST /v1/convert takes the JSON inline and returns the mapped rows in one call, with the routing it used reported on the response.
curl https://api.adaptivmapr.com/v1/convert \
-H "Authorization: Bearer $ADAPTIVMAPR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": { "format": "json", "content": "[{\"subjectRef\":\"S-1\",\"legalName\":\"Muster AG\",\"dob\":\"1984-03-11\"}]" },
"schema": { "ref": "kyc_profiles_v1" },
"output": "json"
}'{
"schema_id": "kyc_profiles_v1",
"source": "template",
"routing": "inline",
"row_count": 1,
"errors": [],
"data": [
{ "subject_id": "S-1", "legal_name": "Muster AG", "date_of_birth": "1984-03-11" }
]
}routing: "inline"on the response means nothing left to a general-data host. Tabular input — json, csv, tsv, xml, sql, xlsx, parquet, and Word/PowerPoint tables — is always parsed in-process.kyc_profiles_v1is high-risk and the flag is derived from that field, not from a per-id list. Add a high-risk template to the catalogue and it is covered automatically.- Convert requires a
schema: either a templateref, a saved custom schema, or an inline definition.POST /v1/schemas/from_textgenerates one from an English description if you do not have one yet. - Uploads (which may carry sensitive data) and connectors (which carry secrets) stay on the service-role plane with explicit
tenant_idscoping. The user-JWT dashboard plane is gated by Supabase RLS.
Where the work lands
Which layer resolves this file
| Layer | What it does here | Auto-accepts at | Cost |
|---|---|---|---|
| 1 · statistics | Header→field pairs confirmed on an earlier batch from the same provider | ≥100 @ 95% · ≥20 @ 100% | Free · deterministic |
| 2 · heuristic | “dob”, “legal name”, “national id”, “risk rating” — shipped hints in five languages | ≥ 0.85 | Free · deterministic |
| 3 · fuzzy | “subjectRef” → subject_id, “countryCode” → country, “verifiedOn” → verified_at | ≥ 0.80 | Free · pure compute |
| 4 · semantic | A provider-specific label with no shared vocabulary | ≥ 0.78 | Cheap, cached · off without an embedding key |
| 5 · ai | One batched call over the leftovers, constrained to the unclaimed field set | Model pick, constrained to the unclaimed column set | Metered · the only paid layer |
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
kyc_profiles_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 limitThe 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 seats or contract; you top up a prepaid wallet from $10 and it draws down.
Rate cardAI 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.
MechanismresolveRunPhi() 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
Does the national_id validator know each country’s scheme?
Our provider uses five risk bands and you have three. What now?
Is identity data PHI?
How long is the uploaded file kept?
Stop hand-mapping this file. Map it once.
Start with a $10 prepaid wallet. In schema-only mode only headers and up to three sample rows — each cell clamped to 80 characters — ever leave you.