ROOSTby Axowl

Docs

Device ledger

axowl.com/dashboard/acme/roost/devices
AxowlacmeRoostM

Devices

2boxes
1pair
0alerts
SerialSiteVotersTamperFirmwareStatus
ROOST-26-0001Seoul HQ, vault floor3/3Armed1.1.0 (B)Green
ROOST-26-0002Busan DR site3/3Armed1.1.0 (B)Green
Chip temp46–50 °C
Mesh100.1 %
TimeNTS · 8 ms
AttestationMatch
Devices: a signed status report every minute, with the pair and the tamper state.

Roost management opens only for an organization that has bought a box. Axowl ships each box to the buying organization, and that organization binds it with the certificate card shipped with the box (see Binding). Until a box is bound, every /api/org/{slug}/roost/* route answers 404 ROOST_NOT_ENABLED, except the five that lead to binding: GET /summary, POST /bind/challenge, POST /bind, POST /airgap/challenge and POST /airgap/import.

Who can open Roost

Only the organization Owner and members holding the fixed Roost Admin role (ROOST_ADMIN) can open the Roost section and call its API. The role carries one scope, view.roost, and is created in every organization like the other preset roles.

  • Fixed. Its name, description and permissions cannot be changed and the role cannot be deleted (403 ROLE_FIXED).
  • Owner assigns it. Only the Owner can assign or revoke it (403 OWNER_REQUIRED for anyone else, Admins included).
  • Admins are not included. view.roost is an Owner-only scope like view.billing: an Admin opens Roost only after the Owner gives them the Roost Admin role.
  • Seal actions stay with the Owner. Binding, pairs, replacement, envelopes, the enrollment ceremony, transfers and re-arm need the Owner and a passkey seal, as before.
  • Auditors see the audit screens only. A Roost Auditor opens the audit log, the auditor list and the log-export settings, nothing else.

Every Roost box an organization owns has a ledger row: serial, model, site, license kind, lifecycle state, the pair it belongs to and its latest signed status report. These endpoints read that ledger. All require the organization Owner or a Roost Admin (403 otherwise). Writes are described in Binding and replacement.

Method · RouteReturns
GET /api/org/{slug}/roost/summary{ deviceCount, pairCount, green, yellow, red, gray, openCases, unacknowledgedRed, awaitingBind, boundCount } — awaitingBind counts boxes shipped to this organization and not bound yet. Answers even before a box is bound.
GET /api/org/{slug}/roost/devicesArray of device rows (below) with status = latest report or null
GET /api/org/{slug}/roost/devices/{serial}{ device, status, pair, events[≤50], enrollment, envelopes, rollouts, maintenance }; 404 ROOST_DEVICE_NOT_FOUND
GET /api/org/{slug}/roost/pairsPairs: deviceA, deviceB, transient (third box during replacement), replacementStep 0–6, envelopes[]
GET /api/org/{slug}/roost/events?serial=&limit=Event timeline, newest first (limit 1–500, default 100)
GET /api/org/{slug}/roost/enrollmentsEnrollment ceremonies: arrival check → measurement compare → quorum registration
GET /api/org/{slug}/roost/roles{ roles[], assignments[], policies[] } — role assignments and quorum per action
GET /api/org/{slug}/roost/maintenanceReplacement, RMA, disposal and module-swap cases
GET /api/org/{slug}/roost/firmware{ releases[], rollouts[] } — signed images and A/B rollout state per box

Device row

{
  "serial": "ROOST-26-0001",
  "displayName": "Seoul HQ A",
  "model": "ROOST-3U",
  "siteName": "Seoul head office, vault floor",
  "country": "KR",
  "siteKind": "CustomerSite",
  "licenseKind": "Connected",
  "lifecycleState": "Active",
  "pairId": "…",
  "isAxowlOperated": false,
  "isDemoUnit": false,
  "shippedAt": "2026-08-20T00:00:00Z",
  "boundAt": "2026-08-25T00:00:00Z",
  "lastReportAt": "2026-10-19T08:00:00Z",
  "status": {
    "color": "Green",
    "quorumOk": true, "votersOnline": 3,
    "psu1Ok": true, "psu2Ok": true, "fansFailed": 0,
    "battery1Mv": 3610, "battery2Mv": 3605, "activeBattery": 1,
    "zeroizeState": "Armed", "keysPresent": true,
    "ntpOk": true, "driftMs": 8,
    "activeSlot": "B", "activeVersion": "1.1.0",
    "signCounter": 89261,
    "reportedAt": "2026-10-19T08:00:00Z",
    "signatureVerified": true
  }
}
  • lifecycleState: Factory · Shipped · Enrolling · Active · Degraded (running 2-of-3) · Zeroized · RmaReturned · Retired · Destroyed.
  • licenseKind: None · Dedicated (Axowl rack) · Connected (customer site + cloud) · AirGapped.
  • status.color: Green · Yellow (warning, after 5 minutes) · Red (alarm, immediate) · Gray (no report for 10 minutes). status is null until the box has reported.
  • zeroizeState: Armed (keys held) · Soft (memory erased after a power loss or failed self-test; keys return after three-party authentication) · Hard (permanent; factory reseal).

The full status in /devices/{serial} adds the three voters (KV260, PolarFire, MachXO3D) with their key ids, the watcher board, mesh resistance ratio, lid / light / EFP switches, seven chip temperatures, board temperature, 12 V / 5 V / 3.3 V, RTC state and the measured hash of each firmware slot.

Events

kind: Tamper · Zeroize · Degraded · Recovered · BatteryLow · BatterySwapped · PowerLoss · PsuFailed · FanFailed · TimeDrift · Rearm · Bound · Enrolled · ReplacementStep · EnvelopeIssued · EnvelopeRevoked · FirmwareCommitted · FirmwareRolledBack · Moved · Disposal. severity: Red · Yellow · Info. auditEventRef links a sealed audit record when the event was produced by a sealed action.

Replacement steps

A failed box is never opened on site. replacementStep on a pair: 1 degraded 2-of-3 → 2 new box staged → 3 joint registration (3 physical keys + Owner quorum seal + Axowl ticket; the pair runs as three boxes) → 4 envelope verified → 5 old box removed → 6 factory resealed.

Audit event names reserved for the ledger (emitted as each write lands): roost.device.bound, roost.device.transferred, roost.device.lifecycle_changed, roost.enrollment.completed, roost.pair.replacement_step, roost.envelope.issued, roost.envelope.revoked, roost.alert.raised, roost.alert.cleared, roost.role.assigned, roost.maintenance.opened, roost.disposal.certified, roost.firmware.released, roost.firmware.committed, roost.test.recorded.