Updates (OTA)¶
The device updates itself over-the-air from a signed update bundle the host pushes over the API — no SD card removal, no console access. It uses two system slots (A/B) so a bad update automatically rolls back instead of bricking the device.
How A/B updates work¶
flowchart TD
A["Slot A: running<br/>(active)"] -->|"PUT /update/bundle"| B["Bundle verified,<br/>installed to Slot B (inactive)"]
B -->|"POST /update/apply"| C["Reboot: trial boot<br/>into Slot B"]
C -->|"Boot succeeds:<br/>waiting page + USB up"| D["displayd marks Slot B good<br/>(rauc mark-good)"]
D --> E["Slot B is now active.<br/>Slot A kept as fallback"]
C -->|"Boot fails / never confirms"| F["Firmware falls back to<br/>Slot A on next watchdog reboot"]
F --> G["update status reports<br/>the rollback"]
The device only ever boots the slot it's currently confirmed-good on, or trials the other slot once; it never gets stuck alternating or stuck unbootable from an update failure by itself.
Check current update status¶
Returns the active slot, each slot's installed version, its health, and the result of the last install (including whether it rolled back).
Web UI: System page — update/slot status.
Upload and install an update bundle¶
curl -X PUT http://10.99.0.1/api/v1/update/bundle \
--data-binary @mycustomerdisplay-2026.07.raucb \
-H 'Content-Type: application/octet-stream'
Returns 202 Accepted with an operation resource while the device streams, cryptographically
verifies (against a keyring baked into the image — an unsigned or wrongly-signed bundle is
rejected), and installs the bundle to the inactive slot. Poll GET
/api/v1/operations/{id} or subscribe to operation events (see Events) to
track progress; the currently running system is untouched throughout this step, so the device
keeps showing whatever it was showing.
Web UI: System page → Upload update bundle.
Apply the update (reboot into the new slot)¶
Uploading does not reboot the device by itself — that's a separate, explicit step so you control exactly when the device goes offline:
This marks the newly-installed slot for the next boot and reboots immediately. The device comes
back up on the new slot; once displayd confirms the browser reached the waiting page and the
USB link is up, it marks that boot good. If it never reaches that point (crash loop, corrupted
install, etc.), the Raspberry Pi firmware automatically falls back to the previous slot on the
next watchdog-triggered reboot — no host action needed to recover, though you should re-check
GET /update afterwards to see the rollback reported.
Web UI: System page → Apply update & reboot.
Planning an update rollout¶
- Push the bundle (
PUT /update/bundle) ahead of time — it doesn't affect the running device, so you can stage it whenever convenient (e.g. overnight) and only callapplyduring a maintenance window. - Always check
GET /updateafterapplyand a reboot to confirm the new slot is active and healthy before considering the rollout for that device done — don't assume success just becauseapplyreturned200. - A power loss between
applyand the trial boot completing falls back to the previous slot silently (the tryboot flag doesn't survive a power cut, only a normal reboot);GET /updatereports this case distinctly from a successful rollback so you can tell "update never really tried" from "update tried and failed". - Because the update is a signed bundle, only bundles built and signed with your release process
will install — building and signing the
.raucbbundle itself is a build-time, not a device-facing, concern; it's outside the scope of this guide.
See also¶
- Configuration — general
PATCH /configsemantics used elsewhere in the API. - Factory reset — wiping the data partition, independent of the OTA slots (a factory reset does not touch which system slot is active).