Skip to content

Trails service ​

/trails implements the heart of Pantahub: each device's trail — the append-only sequence of steps that drives asynchronous configuration management. The model (revisions, the +1 rule, status lifecycle, retries) is explained in Trails & steps; the practical workflow in Deploying updates.

The API has two views: devices create their trail and report progress; owners append steps and read state.

Create a trail (device, first boot) ​

A device creates its own trail exactly once, POSTing its factory state — this becomes revision 0:

sh
curl -s -X POST https://api.pantahub.com/trails/ \
  -H "Authorization: Bearer $DTOKEN" -H 'Content-Type: application/json' \
  -d '{
    "kernel": {"object": "prn:pantahub.com:objects:/<kernel-object-id>"},
    "app":    {"object": "prn:pantahub.com:objects:/<app-object-id>"}
  }'

The trail's id equals the device id; the response tracks tail/tip (oldest/newest revision).

Read steps ​

sh
curl -s https://api.pantahub.com/trails/<trail-id>/steps \
  -H "Authorization: Bearer $TOKEN"

Defaults differ by identity: users get all non-completed steps, devices only steps in state NEW. Query other sets with ?q=<STATE> or ?q=ALL. A single step is addressed by its revision: GET /trails/<trail-id>/steps/<rev>.

Append a step (owner) ​

A new step must carry rev = current tip + 1 — the "first come, first served" rule that rejects concurrent conflicting updates:

sh
curl -s -X POST https://api.pantahub.com/trails/<trail-id>/steps \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{
    "rev": 1,
    "commit-msg": "update app to new release",
    "state": {
      "kernel": {"object": "prn:pantahub.com:objects:/<kernel-object-id>"},
      "app":    {"object": "prn:pantahub.com:objects:/<new-app-object-id>"}
    }
  }'

The step starts in status NEW; the device picks it up on its next walk. (You rarely craft these by hand — pvr post and the UI's device tabs do it for you.)

Report progress (device) ​

The device PUTs to the progress node of the step it is working on as it moves through the lifecycle (QUEUED → INPROGRESS → DONE, or ERROR / WONTGO):

sh
curl -s -X PUT \
  https://api.pantahub.com/trails/<trail-id>/steps/<rev>/progress \
  -H "Authorization: Bearer $DTOKEN" -H 'Content-Type: application/json' \
  -d '{"status":"INPROGRESS","progress":40,"status-msg":"downloading","log":""}'

Step meta ​

Every step also has a free-form meta map for tooling to keep its own bookkeeping, readable and writable by the owner:

sh
curl -s -X PUT https://api.pantahub.com/trails/<trail-id>/steps/<rev>/meta \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"ci-run":"1842","approved-by":"release-bot"}'

GET on the same path reads it back. Meta lives beside the step — it never affects what the device applies.

Endpoint reference ​

Try any of these live in the API Reference:

EndpointReference
POST /trailsCreate trail
GET /trailsList trails
GET /trails/{id}Get trail
GET /trails/{id}/stepsList steps
POST /trails/{id}/stepsAppend step
GET /trails/{id}/steps/{rev}Get step
GET /trails/{id}/steps/{rev}/stateStep state
PUT /trails/{id}/steps/{rev}/progressReport progress
PUT /trails/{id}/steps/{rev}/metaSet step meta
GET /trails/{id}/steps/{rev}/metaGet step meta
PUT /trails/{id}/steps/{rev}/cancelAbort step
GET /trails/{id}/summaryTrail summary
GET /trails/summaryAll-trails summary