---
title: "AI-draft a mapping template from sample records"
method: POST
path: "/api/v1/households/import/draft-mapping"
tags: ["import"]
---

# AI-draft a mapping template from sample records

`POST /api/v1/households/import/draft-mapping`

## Request

- Base URL: `https://worthune.com`
- URL: `https://worthune.com/api/v1/households/import/draft-mapping`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-Api-Key`

A model drafts the declarative template from ≤10 sample records; three deterministic gates (strict JSON, no transcribed numeric consts, the real dry-run over the sample) check it before anything is returned. Nothing is written. 20/hour per org. The drafting model: x-model-key for the request, else your extractor model (model policy), else ours; the response names it.

## Headers

- `x-model-key` string

## Request body

- object
  - `sampleRecords` object[], required: At most 64 distinct columns.
  - `notes` string: Hints for the drafter (what the columns mean).

## Response `200`

The DRAFT template, the model's own unmapped-columns list, and the dry-run over the sample.

- object
  - `ok` unknown, required
  - `draft` unknown, required
  - `template` MappingTemplate, required: Declarative mapping template (docs/data-migration.md), executed server-side over raw exported records.
    - `templateVersion` '0.1.0', required
    - `importKey` union, required: A mapping-template node: { "const": v } for a fixed value; { "column", "parse"?, "optional"?, "map"?, "default"? } to read a source column; an array (elements may add omitIfEmpty: true to be dropped when every referenced column is empty); or a plain object built recursively. Bare literals are template-author errors.
      - object
        - `const` unknown, required
      - object
        - `column` string, required
        - `parse` 'string' | 'number' | 'usd' | 'integer' | 'year': Default string (trimmed). Percent parsing is deliberately absent — rates arrive as fractions via number.
        - `optional` boolean: Empty/absent column omits the key instead of erroring.
        - `map` object: Source value → output value; an unmapped value without a default is an error, never a guess.
        - `default` unknown
      - MappingNode[]
      - object
    - `label` union: A mapping-template node: { "const": v } for a fixed value; { "column", "parse"?, "optional"?, "map"?, "default"? } to read a source column; an array (elements may add omitIfEmpty: true to be dropped when every referenced column is empty); or a plain object built recursively. Bare literals are template-author errors.
      - object
        - `const` unknown, required
      - object
        - `column` string, required
        - `parse` 'string' | 'number' | 'usd' | 'integer' | 'year': Default string (trimmed). Percent parsing is deliberately absent — rates arrive as fractions via number.
        - `optional` boolean: Empty/absent column omits the key instead of erroring.
        - `map` object: Source value → output value; an unmapped value without a default is an error, never a guess.
        - `default` unknown
      - MappingNode[]
      - object
    - `advisorRef` union: A mapping-template node: { "const": v } for a fixed value; { "column", "parse"?, "optional"?, "map"?, "default"? } to read a source column; an array (elements may add omitIfEmpty: true to be dropped when every referenced column is empty); or a plain object built recursively. Bare literals are template-author errors.
      - object
        - `const` unknown, required
      - object
        - `column` string, required
        - `parse` 'string' | 'number' | 'usd' | 'integer' | 'year': Default string (trimmed). Percent parsing is deliberately absent — rates arrive as fractions via number.
        - `optional` boolean: Empty/absent column omits the key instead of erroring.
        - `map` object: Source value → output value; an unmapped value without a default is an error, never a guess.
        - `default` unknown
      - MappingNode[]
      - object
    - `household` object, required: Template tree producing a Household document.
  - `unmappedColumns` object[], required
    - `column` string, required
    - `reason` string, required
  - `sampleDryRun` union, required: The pure import validator's report over the sample (the shape behind the import route's rows).
    - object
      - `ok` unknown, required
      - `rows` unknown[], required
        - unknown
      - `dryRun` boolean, required
    - object
      - `ok` unknown, required
      - `errors` ValidationIssue[], required
        - `path` string: JSON-path-ish locator into the request, e.g. "accounts[2].balance".
        - `message` string, required
      - `valid` unknown[], required
        - unknown
      - `invalid` unknown[], required
        - unknown
      - `dryRun` boolean, required
  - `drafter` Drafter, required: Which model drafted. The deterministic gates after it are the same whichever it was.
    - `source` 'caller-key' | 'organization-policy' | 'deployment', required: x-model-key for this request, else your organization's role model (PUT /api/v1/model-policy), else the deployment's.
    - `provider` 'anthropic' | 'gemini' | 'openai-compatible' | 'azure-openai', required
    - `model` string, required
  - `note` string, required

## Other responses

- `400`: Malformed JSON, a body of the wrong shape, or a top-level field that fails its check.
- `401`: No key presented (Authorization: Bearer wk_… or X-Api-Key).
- `402`: Unrecognized or revoked API key.
- `403`: The key's role is below the operation's floor (viewer < developer < owner), the key predates organization support, or the plan lacks the feature. On a sandbox key, also: the cap of 5 active households on create and import, the cap of 1 active Lodestar mandate, and the white-label surfaces (tenant config, embed tokens) and narration or mapping drafts on Worthune's model (they run on your own: a model assigned at /api/v1/model-policy, or x-model-key), which the sandbox does not carry.
- `422`: sampleRecords/notes failed validation.
- `429`: Hourly per-org stateful quota, a per-route durable limit, or the 120 requests/minute per-IP burst backstop.
- `502`: The model did not answer, did not return a template, or transcribed numbers (guardPaths names them).
- `503`: No drafting model is configured on this deployment (or billing is not configured).

---

[API](https://skmtc.dev/worthune/apis/worthune-api.md) · [All operations](https://skmtc.dev/worthune/apis/worthune-api/llms.txt) · [OpenAPI document](https://skmtc.dev/worthune/apis/worthune-api/revisions/9f2241072555?raw)
