Templates
A template is a reusable schema blueprint — a tree of levels (root A, children assigned breadth-first), each typed singular, series, or many and carrying property definitions. Templates are either your team's own (visibility: "team", category: "custom") or part of the shared public catalog (battery, textile, electronics, furniture). Shape one in a draft, complete it to freeze it, then instantiate it as an ontology.
The template model
- Name
object- Type
- string
- Description
Always
template.
- Name
id- Type
- string
- Description
Unique identifier, e.g.
template_00a1b2c3d4e5f607.
- Name
name- Type
- string
- Description
Display name (3–30 characters). Nullable.
- Name
description- Type
- string
- Description
Short description (3–255 characters). Nullable.
- Name
status- Type
- string
- Description
draftorcomplete. Completed templates are immutable.
- Name
category- Type
- string
- Description
custom(your team's) or a public catalog category —battery,textile,electronics,furniture. Nullable.
- Name
visibility- Type
- string
- Description
teamorpublic.
- Name
forked_from- Type
- object
- Description
Provenance recorded when the template was forked: the source's
template_id,nameandcategory, captured at fork time and never refreshed. Null on a template that was not forked.
- Name
structure- Type
- object
- Description
The level tree, keyed by level key (see below). Nullable on a fresh draft.
- Name
metadata- Type
- object
- Description
Caller-owned metadata bag. Always present,
{}when empty. Patchable on acompletetemplate, which is otherwise immutable — completion freezes the schema, not your bookkeeping. Send any other field alongside it and the request takes the ordinary update path, immutability check included.
- Name
created_at- Type
- string
- Description
ISO 8601 timestamp of creation.
- Name
updated_at- Type
- string
- Description
ISO 8601 timestamp of the last update.
The structure document
structure is a map of level key → level node. Each node carries its type, its parent/children wiring, and its property definitions. PATCH replaces the whole document.
structure
{
"A": {
"id": "A", "name": "SKU", "type": "singular", "is_root": true,
"granularity": "model", "static_lineage": true,
"properties": [], "children": ["B"]
},
"B": {
"id": "B", "name": "Pack", "type": "series", "is_root": false,
"granularity": "batch", "static_lineage": true, "parent": "A", "children": [],
"properties": [
{ "id": "property_9f2k7d", "name": "Capacity", "type": "measurement",
"value": { "required": true }, "data_element_id": "BATT-BATCH-CAP" },
{ "id": "property_3c8n1q", "name": "Produced On", "type": "date",
"value": { "required": false,
"requirements": { "future": true, "past": true, "current": true } },
"visibility": { "internal": true, "auditors": true,
"partners": true, "public": true } }
]
}
}
Each level needs a name and a type of singular, series, or many. children defines the edges; parent is filled in from them when omitted. The root level A must always exist, and exactly one level must carry is_root: true — that flag, not the key, is what selects the root. Don't send static_lineage: the server derives it from the shape of the tree (a level has static lineage when no ancestor is many or series) and overwrites anything you provide.
A malformed structure — an unknown type, a missing name, no root or two, a level unreachable from the root, a child that doesn't exist, or a series under a many — is rejected with 400 parameter_invalid, so it can never reach an ontology. See the Data model for how level types behave.
A level may also carry a granularity — model, batch, or item, the tier it reports as to the EU registry — and is_core, marking the level the registry is given as that tier's ID. Leave both out for a level that is internal only; in structure they appear only where they are set. The rules are the ones ontologies enforce — see reporting granularity — and a template write that breaks one is 400 parameter_invalid, with the message under the offending level's structure.<key> entry in error.errors. Whether every reported tier has its core is checked when you complete the template.
Property type values are short_text, long_text, number, measurement, boolean, date, tags, range, file, image, plus the non-editable category and composite.
Property definitions
Each entry in a level's properties array is validated on write. A malformed definition fails the whole request with 400 parameter_invalid, and error.param points at the exact property — e.g. structure.B.properties.0.value.
- Name
id- Type
- string
- Description
Unique within the level; a duplicate is rejected. Minted by the server when omitted. Ontology instantiation regenerates every property id regardless — read ids from the ontology, never the template.
- Name
name- Type
- string
- Description
Display name. Required, non-empty.
- Name
type- Type
- string
- Description
One of the property types listed above. Anything else is rejected.
- Name
value- Type
- object
- Description
Type-specific configuration.
requireddefaults tofalseand must be a boolean when sent. Fordatepropertiesvaluemust be an object, andvalue.requirements.{future, past, current}— which dates a passport may hold — each default totruewhen omitted. Acategorydivider's value is its label string. Other keys are stored as sent.
- Name
visibility- Type
- object
- Description
Which audiences see the property's values on rendered passports:
internal,auditors,partners,public. Each flag must be a boolean when present. A missing flag — or omitting the object entirely — hides the property from that audience, so send it explicitly if the data should be visible anywhere.
- Name
data_element_id- Type
- string
- Description
The EU registry's own name for the field this property's values are reported as. Leave it out — the ordinary case — and the property is not reported. Allowed only on a level with a
granularity, one property per element per tier, at most 128 characters with no control characters; trimmed on write, and a blank value is stored as no mapping. See reported properties.
No flag on a definition makes a property translatable: short_text, long_text, tags, and file values hold one value per language by their type. See passports.
List templates
Lists your team's own templates (category=custom, the default) or the shared public catalog. Returns a paginated list. Requires templates:read.
Optional attributes
- Name
category- Type
- string
- Description
custom(default),battery,textile,electronics, orfurniture.
- Name
created[gte]- Type
- string
- Description
Only templates created at or after this time. Unix seconds or an ISO date, inclusive of the whole second named.
- Name
created[lte]- Type
- string
- Description
Only templates created at or before this time. An inverted range is
400.
- Name
limit- Type
- integer
- Description
Page size, 1–100 (default 10).
- Name
cursor- Type
- string
- Description
A pagination cursor from a previous response's
next_cursor.
The creation window runs as a key condition and does not scan. This is the one list of the three that can still return a short page, and only because the category post-filter applies after the page is read — page until has_more is false. Filters join the cursor's scope; see pagination.
Request
curl -G https://api.synexcloud.com/v1/templates \
-H "Authorization: Bearer $SYNEX_API_KEY" \
-d category=battery \
-d limit=10
Response
{
"object": "list",
"data": [
{
"object": "template",
"id": "template_00a1b2c3d4e5f607",
"name": "EV Battery Pack",
"description": "48V modular pack blueprint",
"status": "complete",
"category": "battery",
"visibility": "public",
"forked_from": null,
"structure": { "A": { "id": "A", "type": "singular" } },
"metadata": {},
"created_at": "2026-07-01T08:00:00Z",
"updated_at": "2026-07-01T08:00:00Z"
}
],
"has_more": false,
"next_cursor": null,
"url": "/v1/templates"
}
Create a draft template
Creates a draft template with an empty root level A. Shape its structure with PATCH, then finalize it with complete. Requires templates:write. Accepts an optional Idempotency-Key header.
Required attributes
- Name
name- Type
- string
- Description
Display name, 3–30 characters.
- Name
description- Type
- string
- Description
Short description, 3–255 characters.
Optional attributes
- Name
metadata- Type
- object
- Description
Initial metadata bag.
Request
curl https://api.synexcloud.com/v1/templates \
-H "Authorization: Bearer $SYNEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Battery blueprint", "description": "48V modular pack" }'
Response
{
"object": "template",
"id": "template_11b2c3d4e5f60718",
"name": "Battery blueprint",
"description": "48V modular pack",
"status": "draft",
"category": "custom",
"visibility": "team",
"forked_from": null,
"structure": {
"A": { "id": "A", "name": "SKU", "type": "singular", "is_root": true }
},
"metadata": {},
"created_at": "2026-07-12T09:31:00Z",
"updated_at": "2026-07-12T09:31:00Z"
}
Retrieve a template
Retrieves one of your team's templates or a public one by id. Requires templates:read.
Request
curl https://api.synexcloud.com/v1/templates/template_11b2c3d4e5f60718 \
-H "Authorization: Bearer $SYNEX_API_KEY"
Response
{
"object": "template",
"id": "template_11b2c3d4e5f60718",
"name": "Battery blueprint",
"description": "48V modular pack",
"status": "draft",
"category": "custom",
"visibility": "team",
"forked_from": null,
"structure": { "A": { "id": "A", "type": "singular", "is_root": true } },
"metadata": {},
"created_at": "2026-07-12T09:31:00Z",
"updated_at": "2026-07-12T09:31:00Z"
}
Update a draft template
Updates a draft's name, description, and/or structure. Completed templates are immutable — updating one fails with 409 template_not_draft, unless the patch carries only metadata. Requires templates:write.
Fields you omit are left unchanged; an explicit null has the same effect and does not clear the value.
A template is stored as one document, so the whole thing — every level,
every property definition, its name and description — must stay under
400 KB. A patch that would cross that is rejected with 413
template_too_large and nothing is written.
Optional attributes
- Name
name- Type
- string
- Description
Display name, 3–30 characters.
- Name
description- Type
- string
- Description
Short description, 3–255 characters.
- Name
structure- Type
- object
- Description
The full replacement level tree, keyed by level key. The root level
Amust exist, and every property definition is validated and normalized — missing property ids are minted, and daterequirementsare filled with their defaults. Levels and properties are checked against the granularity and data element rules on every write.
- Name
metadata- Type
- object
- Description
Merged per key; a null value deletes that key. Accepted on a completed template too, when it is the only field sent.
Request
curl -X PATCH https://api.synexcloud.com/v1/templates/template_11b2c3d4e5f60718 \
-H "Authorization: Bearer $SYNEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"structure": {
"A": { "id": "A", "name": "SKU", "type": "singular", "is_root": true,
"granularity": "model", "children": ["B"] },
"B": { "id": "B", "name": "Pack", "type": "series", "parent": "A",
"granularity": "batch",
"properties": [{ "id": "property_9f2k7d", "name": "Capacity", "type": "measurement" }] }
}
}'
Response
{
"object": "template",
"id": "template_11b2c3d4e5f60718",
"status": "draft",
"structure": {
"A": { "id": "A", "name": "SKU", "type": "singular", "is_root": true,
"granularity": "model", "children": ["B"] },
"B": { "id": "B", "name": "Pack", "type": "series", "parent": "A",
"granularity": "batch" }
},
"updated_at": "2026-07-12T09:40:00Z"
}
Fork a template
Creates a new draft copy of a completed template — your own or a public one — recording provenance in forked_from. Drafts cannot be forked (409 template_is_draft). Requires templates:write. Accepts an optional Idempotency-Key header.
Required attributes
- Name
name- Type
- string
- Description
Display name for the fork, 3–30 characters.
- Name
description- Type
- string
- Description
Short description, 3–255 characters.
Request
curl https://api.synexcloud.com/v1/templates/template_00a1b2c3d4e5f607/fork \
-H "Authorization: Bearer $SYNEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "EV Pack (Acme)", "description": "Battery pack, Acme variant" }'
Response
{
"object": "template",
"id": "template_22c3d4e5f6071829",
"name": "EV Pack (Acme)",
"description": "Battery pack, Acme variant",
"status": "draft",
"category": "custom",
"visibility": "team",
"forked_from": {
"template_id": "template_00a1b2c3d4e5f607",
"name": "EV Battery Pack",
"category": "battery"
},
"metadata": {},
"created_at": "2026-07-12T10:00:00Z",
"updated_at": "2026-07-12T10:00:00Z"
}
Complete a template
Finalizes a draft. Completed templates are immutable and can be forked or instantiated into ontologies. Requires templates:write. Accepts an optional Idempotency-Key header.
Completion checks that every reported tier has its one core — the level marked is_core — placed where every path through the tier passes through it. A tier carried by a single level is settled for you: there is only one candidate, so that level is marked is_core and the completed template stores it. A tier carried by several levels is yours to pick, and completion fails with 400 structure_invalid, the message under the level's structure.<key> entry in error.errors, until you do. A refused completion writes nothing, so the levels it could have settled stay as they were.
Request
curl -X POST https://api.synexcloud.com/v1/templates/template_11b2c3d4e5f60718/complete \
-H "Authorization: Bearer $SYNEX_API_KEY"
Response
{
"object": "template",
"id": "template_11b2c3d4e5f60718",
"name": "Battery blueprint",
"status": "complete",
"visibility": "team",
"structure": {
"A": { "id": "A", "name": "SKU", "type": "singular", "is_root": true,
"granularity": "model", "is_core": true, "children": ["B"] },
"B": { "id": "B", "name": "Pack", "type": "series", "parent": "A",
"granularity": "batch", "is_core": true }
},
"updated_at": "2026-07-12T10:05:00Z"
}
Delete a draft template
Deletes a draft template. Only drafts can be deleted — deleting a completed template fails with 409 template_not_draft. Requires templates:write.
Request
curl -X DELETE https://api.synexcloud.com/v1/templates/template_11b2c3d4e5f60718 \
-H "Authorization: Bearer $SYNEX_API_KEY"
Response
{
"object": "template",
"id": "template_11b2c3d4e5f60718",
"deleted": true
}