ROOSTby Axowl

Docs

Maintenance, disposal and firmware

There is no on-site repair. The rear battery slot, PSU modules and fan modules are swapped without opening the enclosure; anything else means replacing the whole box, which is then factory resealed. Disposal ends with a signed certificate.

Method · RouteWhoEffect · audit event
POST /api/org/{slug}/roost/maintenanceOwner / Roost AdminOpen a case { serial, kind (Replacement | Rma | Disposal | BatterySwap | PsuSwap | FanSwap), reason }. roost.maintenance.opened
POST /api/org/{slug}/roost/maintenance/{id}/advanceapprove = Owner seal (roost.maintenance, RoostMaintenanceSubject(slug, "approve", caseId)); start, reseal, close = Owner / Roost AdminOpen → Approved → InProgress → FactoryReseal (replacement / RMA) → Closed. A module swap closes only with details JSON and writes the swap on the box timeline. 409 CASE_STEP_OUT_OF_ORDER
POST /api/org/{slug}/roost/maintenance/{id}/disposeOwner seal (RoostMaintenanceSubject(slug, "dispose", caseId))Issues the disposal certificate, closes the case, the box becomes Destroyed. roost.disposal.certified, roost.device.lifecycle_changed
GET /api/org/{slug}/roost/maintenance/{id}/certificateOwner / Roost AdminThe certificate and the public key to verify it
POST /api/org/{slug}/roost/firmware/rollouts/{id}/rollbackOwner seal (roost.firmware, RoostFirmwareSubject(slug, "rollback", rolloutId))Verified / Committed → RollbackRequested; the box reports RolledBack

Disposal certificate

base64url(payload) "." base64url(signature) — ECDSA P-256 / SHA-256 r‖s with the Roost identity key (not the re-arm key). Payload (UTF-8 JSON): { v: 1, typ: "roost-disposal", serial, model, org, caseId, lastKeysPresent, lastZeroizeState, lastReportAt, signCounter, approvedBy, disposedBy, at, reason }. Verify the signature over the payload bytes as received; certificateHash is the SHA-256 of those bytes. Without a configured identity key the endpoint answers 503 ROOST_IDENTITY_KEY_MISSING.

Firmware rollout (box side)

Both calls use the same signed envelope as /api/roost/report ({ serial, payload, signature }, attestation key).

Method · RoutePurpose
POST /api/roost/rollout-pollpayload = { at }. Returns { serial, rollouts[{ rolloutId, state (Pending | RollbackRequested), target, version, imageHash, signatureKid, channel }] }
POST /api/roost/rollout-statuspayload = { rolloutId, state, slot?, failureReason?, at }. state: Downloaded → Staged → Verified → Committed, or RolledBack from any state. Steps must advance one at a time (409 ROLLOUT_STEP_OUT_OF_ORDER). Committed and RolledBack write roost.firmware.committed

The box downloads the image from the release store, checks the signature with its pinned key, writes the free slot, self-tests and commits; a failed self-test rolls back. Downgrades and images for another board are refused by the box.