Synthesize a Template
POST /v1/templates/synthesize — read a piece of legacy ZPL and get back a clean Template draft: a body with ^FN placeholders, a field map naming them, sample values, and a confidence score.
curl -X POST https://api.maddoxapi.dev/v1/templates/synthesize \
-H "Authorization: Bearer $MADDOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input_zpl": "^XA^FO50,50^A0N,30,30^FDMER-04821^FS^XZ",
"target_scope": "tenant",
"target_tenant_id": "tnt_4f9c2a1b7e0d3c5a8b1f6e2d"
}'The draft is not stored; commit it separately to make it a reusable Template. See the Synthesis concept for the bigger picture.
Endpoint#
POST /v1/templates/synthesizeAuthentication: Bearer API key. The tenant is derived from your key.
Request Body#
Content-Type: application/json. Maximum body size 64 KB.
| Field | Type | Required | Description |
|---|---|---|---|
input_zpl | string | yes | The legacy ZPL to synthesize. Non-empty; ≤ 64 KB. |
target_scope | string | yes | Must be "tenant". ("global" is operator-only.) |
target_tenant_id | string · null | no | Your tenant id (tnt_…). Optional — the effective tenant is derived from your API key; if you pass it, it must match. |
hint_template_id | string · null | no | If you plan to commit under a known id, pass it; echoed back as template_id. |
hint_field_names | string[] · null | no | Optional hints for what to name the fields. |
NoteYou only ever synthesize at
tenant scope, into your own tenant. The worker coerces the scope/tenant from your API key, so you can't synthesize into someone else's account.Response#
200 OK
{
"status": "ok",
"scope": "tenant",
"tenant_id": "tnt_4f9c2a1b7e0d3c5a8b1f6e2d",
"draft": {
"name": "asset_label",
"width_dots": 812,
"height_dots": 1218,
"source_dpi": 203,
"body": "^XA^FO50,50^A0N,30,30^FN1^FS^XZ",
"field_map": { "asset_label_text": 1 },
"values": { "asset_label_text": "MER-04821" }
},
"confidence_score": 0.91,
"low_confidence": false,
"warnings": [],
"_synthesis_meta": { "model": "claude-haiku", "prompt_version": "baseline_v3" }
}| Field | Type | Description |
|---|---|---|
draft.body | string | Cleaned ZPL with ^FN placeholders where the variable data was. |
draft.field_map | object | { name: fn_number } — fill fields by name. |
draft.values | object | { name: value } — the sample data lifted out of input_zpl. |
draft.width_dots / height_dots / source_dpi | number · null | Detected label dimensions and authoring DPI. |
confidence_score | number | 0–1 trust score for the draft. |
low_confidence | boolean | true when the score is below the review threshold. |
confidence_components | object | Per-signal breakdown behind the score. |
_synthesis_meta | object | Schema/model/prompt versions and a per-call request_id. |
CautionSynthesis returns a draft, not a stored Template. Review it (especially when
low_confidence is true) and commit it under a template_id to make it renderable via POST /v1/labels/from-data.Quota#
Each successful call consumes one unit of your plan's monthly synthesis quota. When the quota is exhausted you get a 402-class response with an upgrade path. See Plans & Quotas.
Error Codes#
| Status | kind | Cause |
|---|---|---|
| 400 | InvalidJson | Body is not valid JSON. |
| 401 | PRE_AUTH_UNAUTHORIZED | Missing, invalid, or revoked API key. |
| 402 | (quota gate kind) | Monthly synthesis quota reached; includes an upgrade prompt. |
| 422 | InvalidInputZpl | input_zpl missing, empty, or over the 64 KB cap. |
| 422 | InvalidScopeForTenantCall | A tenant call requested target_scope: "global". |
| 422 | InvalidTenantId | target_tenant_id missing or malformed. |
| 502 | (synthesis upstream) | The synthesis model was temporarily unavailable. Retriable. |
Related#
Synthesis (concept)
Why synthesis exists and how to read the confidence score.
Templates & Field Maps
What a draft becomes once committed.