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 (QUEUEDINPROGRESSDONE, 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