When an operator syncs a cookbook to a device, the backend publishes a
request over MQTT. Instead of embedding every recipe template in the message, things5
sends a link to a manifest you download over HTTPS, so the MQTT
payload stays small no matter how many recipes the cookbook contains.
1. Request (backend → device)
Topic:
things5/v1/devices/<DEVICE_ID>/cmd/sync_recipe_templates_v2_req
Payload:
{
"request_id": "<uuid>",
"cookbook_sync_log_id": "<uuid>",
"manifest_url": "https://...signed-url...",
"expires_at": 1779711048527
}
- manifest_url — pre-signed HTTPS URL to the manifest. Valid until
expires_at (Unix epoch, milliseconds). Download it before then.
- request_id / cookbook_sync_log_id — echo both back in your response.
2. Manifest (device downloads from manifest_url)
{
"manifest_version": 1,
"cookbook_sync_id": "<uuid>",
"recipes": [
{
"index": 0,
"id": "<uuid>",
"hash": "<sha256-hex>",
"hash_version": 1,
"url": "https://.../recipes/0.json"
}
]
}
For each entry, compare hash against the recipe you already have stored
locally:
- Same hash → you already have this recipe, skip the download.
- Different/missing hash, or hash_version you don't support →
download url.
The hash is a content fingerprint (algorithm versioned by hash_version).
This lets you re-sync a cookbook and only fetch what actually changed.
3. Recipe (device downloads from each url)
{
"id": "<uuid>",
"index": 0,
"name": "...",
"description": "...",
"machine_model_id": "<uuid>",
"phases": [ ... ],
"metadata": [ ... ],
"hash": "<sha256-hex>",
"hash_version": 1
}
Apply it and free the buffer before fetching the next one (you don't need
to hold the whole cookbook in memory).
4. Response (device → backend)
Topic:
things5/v1/devices/<machine_id>/cmd/sync_recipe_templates_res
Payload:
{
"request_id": "<uuid>",
"cookbook_sync_log_id": "<uuid>",
"synced_at": 1779711048527,
"errors": []
}
- Echo request_id and cookbook_sync_log_id from the request.
- synced_at — Unix epoch (ms) when the sync completed.
- errors — empty array on success, otherwise one string per failure.
▎ The response is identical to v1, so the backend correlates v1 and v2
▎ the same way. A device that supports v2 subscribes to the
▎ ..._v2_req topic; legacy devices keep using ..._req.
