Passports
A passport — a digital product passport (DPP) — is one product data record at a level of an ontology. Every passport has a globally unique id, a path within its ontology, optional property values, and a publish_status that can be set explicitly or inherited from its ancestors. Passports are addressed two ways: by their universal id, or by their path.
New to the model? Read the Data model first — it explains levels, the Singular/Series/Many types, paths (TPPMP), and how publish status is inherited. This page assumes those concepts.
The passport model
- Name
object- Type
- string
- Description
Always
passport.
- Name
id- Type
- string
- Description
Unique, universal identifier, e.g.
pass_00a1b2c3d4e5f607. Resolves any passport at any depth viaGET /v1/passports/:id.
- Name
ontology- Type
- string
- Description
The id of the ontology this passport belongs to. Nullable.
- Name
parent- Type
- string
- Description
The parent passport's id.
nullfor the root.
- Name
level- Type
- string
- Description
The level key this passport sits at (e.g.
A,B). Nullable.
- Name
path- Type
- string
- Description
The passport's position within the ontology: the level key alone for the root (
A), otherwiseLEVEL:snowflake[/snowflake]. The snowflake segments are bare — nopass_prefix — and apathread off one response is a valid?path=argument on the next. Encoded as the TPPMP sort key, e.g.B:07c9…. Nullable.
- Name
friendly_id- Type
- string
- Description
Optional human-readable alias, unique within the parent. Nullable.
- Name
publish_status- Type
- string
- Description
The explicit status:
published,draft, orarchived.nullmeans it inherits from the parent chain.
- Name
publish_status_resolved- Type
- string
- Description
The effective status after inheritance (present on detail reads only).
- Name
values- Type
- object
- Description
Property values, keyed by the ontology's property ids. Always a JSON object —
{}when the passport has no values yet, never[]— so the field's type never changes with its contents.
- Name
ontology_version- Type
- integer
- Description
The ontology version this passport is pinned to — the one it was created under. Reads render against this version's levels, and writes validate against its property definitions.
- Name
metadata- Type
- object
- Description
Caller-owned metadata bag. Always present,
{}when empty.
- 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 pin is what a write is validated against. A property added in a later
ontology version is rejected on an older-pinned passport. Creation surfaces
are the exception — creating a passport or starting an import
validates against latest_version and pins the new passport to it, so a level
added in a new version is immediately creatable under a parent still pinned to
an old one.
Detail reads
A full detail read (GET /v1/passports/:id and the find endpoint) also includes traversal info:
- Name
discoverable_levels- Type
- array
- Description
The child levels reachable from this passport when rendering its public page.
- Name
discovery_chain- Type
- array
- Description
The level traversal used to assemble the full passport.
List passports at a path
Lists — or searches — the passports under a path within an ontology. Paths start with the level key: B lists the series at level B; deeper paths address a specific branch. Returns a paginated list. Requires passports:read.
Required attributes
- Name
path- Type
- string
- Description
The path to list under, e.g.
B.
Optional attributes
- Name
search- Type
- string
- Description
Free-text search within the level (up to 100 characters).
- 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.
Request
curl -G https://api.synexcloud.com/v1/ontologies/ontology_00a1b2c3d4e5f607/passports \
-H "Authorization: Bearer $SYNEX_API_KEY" \
-d path=B \
-d limit=10
Response
{
"object": "list",
"data": [
{
"object": "passport",
"id": "pass_11b2c3d4e5f60718",
"ontology": "ontology_00a1b2c3d4e5f607",
"parent": "pass_00a1b2c3d4e5f607",
"level": "B",
"path": "B:07c9f2a1b3d4e5f6",
"friendly_id": "PACK-001",
"publish_status": "published",
"values": { "property_9f2k7d": "4500" },
"created_at": "2026-07-12T09:35:00Z",
"updated_at": "2026-07-12T09:40:00Z"
}
],
"has_more": false,
"next_cursor": null,
"url": "/v1/ontologies/ontology_00a1b2c3d4e5f607/passports"
}
Create a passport
Creates a passport at a level of the ontology, under a parent passport — start from the ontology's root_passport. singular levels allow one passport per parent (a second fails with 409 passport_exists_at_level); series and many levels allow any number. You never create level A — the root passport is created with the ontology, and trying to create it under a parent is a 400 parameter_invalid on level. The parent must also sit at the level the ontology declares as level's parent: you can't skip a level (creating C directly under an A) or hang a passport off the wrong branch — a mismatch is a 400 parameter_invalid on parent, and nothing is written. Requires passports:write. Accepts an optional Idempotency-Key header.
Required attributes
- Name
parent- Type
- string
- Description
The parent passport's id.
- Name
level- Type
- string
- Description
The level key to create at (e.g.
B).
Optional attributes
- Name
friendly_id- Type
- string
- Description
Human-readable alias, unique within the parent (
409friendly_id_takenotherwise).
Request
curl https://api.synexcloud.com/v1/ontologies/ontology_00a1b2c3d4e5f607/passports \
-H "Authorization: Bearer $SYNEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "parent": "pass_00a1b2c3d4e5f607", "level": "B", "friendly_id": "PACK-001" }'
Response
{
"object": "passport",
"id": "pass_11b2c3d4e5f60718",
"ontology": "ontology_00a1b2c3d4e5f607",
"parent": "pass_00a1b2c3d4e5f607",
"level": "B",
"path": "B:07c9f2a1b3d4e5f6",
"friendly_id": "PACK-001",
"publish_status": null,
"values": {},
"created_at": "2026-07-12T09:35:00Z",
"updated_at": "2026-07-12T09:35:00Z"
}
Find a passport by path
Returns the single passport at an exact path, with full traversal detail. Use this when you know a passport's position (e.g. the root at path A) rather than its id. Requires passports:read.
Required attributes
- Name
path- Type
- string
- Description
The exact path, e.g.
Afor the root.
Request
curl -G https://api.synexcloud.com/v1/ontologies/ontology_00a1b2c3d4e5f607/passports/find \
-H "Authorization: Bearer $SYNEX_API_KEY" \
-d path=A
Response
{
"object": "passport",
"id": "pass_00a1b2c3d4e5f607",
"ontology": "ontology_00a1b2c3d4e5f607",
"parent": null,
"level": "A",
"path": "A",
"friendly_id": null,
"publish_status": "published",
"publish_status_resolved": "published",
"values": { "property_11a0f3": "EV-PACK-48V" },
"discoverable_levels": ["B"],
"discovery_chain": [{ "level": "A", "type": "singular" }],
"created_at": "2026-07-10T12:00:00Z",
"updated_at": "2026-07-12T09:40:00Z"
}
Retrieve a passport
Retrieves a passport by its universal id — this works for any passport at any depth, without knowing its ontology or path. It's a full detail read: values (file and image values carry short-lived download links), the resolved publish status, and traversal info. Requires passports:read.
A retrieve records a read audit event — every read
of a passport is logged, whether from the app or the API.
Request
curl https://api.synexcloud.com/v1/passports/pass_11b2c3d4e5f60718 \
-H "Authorization: Bearer $SYNEX_API_KEY"
Response
{
"object": "passport",
"id": "pass_11b2c3d4e5f60718",
"ontology": "ontology_00a1b2c3d4e5f607",
"parent": "pass_00a1b2c3d4e5f607",
"level": "B",
"path": "B:07c9f2a1b3d4e5f6",
"friendly_id": "PACK-001",
"publish_status": "published",
"publish_status_resolved": "published",
"values": {
"property_9f2k7d": "4500",
"property_datasheet": { "url": "https://files.synexcloud.com/...", "expires_at": "2026-07-12T10:10:00Z" }
},
"discoverable_levels": ["C"],
"discovery_chain": [
{ "level": "B", "type": "series" },
{ "level": "C", "type": "many" }
],
"created_at": "2026-07-12T09:35:00Z",
"updated_at": "2026-07-12T09:40:00Z"
}
Update a passport
Updates any combination of property values, friendly_id, and publish_status in one call. All values are validated against the ontology's property definitions before anything is written — a single bad value fails the whole values group with 400 value_invalid and per-property errors; valid values are then applied. Every change writes an audit event. Requires passports:write.
Optional attributes
- Name
values- Type
- object
- Description
A map of property id → new raw value.
- Name
friendly_id- Type
- string
- Description
A new human-readable alias, unique within the parent.
- Name
publish_status- Type
- string
- Description
published,draft,archived, orautomatic. Settingautomaticclears the explicit status so the passport inherits again.
series levels with fully static ancestry never inherit published —
publishing each instance is an explicit decision. See the series release
gate.
Request
curl -X PATCH https://api.synexcloud.com/v1/passports/pass_11b2c3d4e5f60718 \
-H "Authorization: Bearer $SYNEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"values": { "property_9f2k7d": 4500, "property_material": "Graphite" },
"friendly_id": "PACK-001-R2",
"publish_status": "published"
}'
Response
{
"object": "passport",
"id": "pass_11b2c3d4e5f60718",
"ontology": "ontology_00a1b2c3d4e5f607",
"level": "B",
"path": "B:07c9f2a1b3d4e5f6",
"friendly_id": "PACK-001-R2",
"publish_status": "published",
"values": { "property_9f2k7d": 4500, "property_material": "Graphite" },
"updated_at": "2026-07-12T09:45:00Z"
}
Dates
A date value is stored as the calendar day it names, always normalized to YYYY-MM-DD. The response echoes back that canonical form — a different string than you sent whenever you write another spelling — which is what keeps dates sortable and comparable with PassQL >, <, and between.
Accepted on write: 2026-07-22, 2026/07/22, 22 Jul 2026, July 22, 2026, 20260722, and ISO 8601 datetimes such as 2026-07-22T10:30:00Z (truncated to the day they name, with no timezone shift).
Rejected with 400 value_invalid / invalid_date: days that don't exist (2026-02-30, 2026-02-29), years outside four digits (99999-01-01), and relative expressions (next tuesday, tomorrow, +1 day) — a value whose meaning changes every time it's read is not a date.
Numeric dates are never guessed at
Whether 03/04/2026 means 3 April or 4 March is a fact about the writer's locale, not about the string, so the API refuses to pick one. A separator-delimited numeric date is rejected with 400 ambiguous_date whenever both readings are real days:
| Sent | Stored | Why |
|---|---|---|
13/05/2026 | 2026-05-13 | only day-first is a real date |
05/13/2026 | 2026-05-13 | only month-first is a real date |
03/03/2026 | 2026-03-03 | both readings agree |
03/04/2026 | 400 ambiguous_date | 3 April and 4 March are both real |
The same applies to - and . separators. Send YYYY-MM-DD and none of this applies to you.
This is deliberately strict for MM/DD/YYYY sources: a US-locale spreadsheet
pushed through imports fails on the rows whose day is 12 or less
and imports the rest. Rows are validated one at a time, so a rejected row is
simply never created — it lands in the import's failed rows with the
ambiguous_date cell named. Read them back with GET /v1/imports/:id/rows,
convert the column to YYYY-MM-DD at the source, and retry. Nothing has to be
un-imported, because the ambiguous values were never written.
Delete a passport
Deletes the passport and releases its friendly_id for reuse within the parent. Requires passports:write.
Request
curl -X DELETE https://api.synexcloud.com/v1/passports/pass_11b2c3d4e5f60718 \
-H "Authorization: Bearer $SYNEX_API_KEY"
Response
{
"object": "passport",
"id": "pass_11b2c3d4e5f60718",
"deleted": true
}
Download a passport's QR code
Renders the QR code linking to the passport's public page — the same link the Synex app prints. Returns binary image data, so write it straight to a file. Requires passports:read.
Optional attributes
- Name
format- Type
- string
- Description
png(default),jpg,svg, orpdf.
- Name
size- Type
- integer
- Description
Pixel size, 64–2048 (default 512). A value outside that range is rejected with
400parameter_invalidrather than clamped.
Request
curl -G https://api.synexcloud.com/v1/passports/pass_11b2c3d4e5f60718/qr \
-H "Authorization: Bearer $SYNEX_API_KEY" \
-d format=png \
-d size=1024 \
-o passport-qr.png
Response
HTTP/1.1 200 OK
Content-Type: image/png
(binary QR image — PNG, JPG, SVG, or PDF per the `format` parameter)