Relayer logoRelayer

Device updates

The update-check contract: one GET request, staged rollouts, update policies.

The contract

GET /u/<appRef>/<channel>/<platform>/<arch>/<currentVersion>
HeaderPurpose
X-Relayer-DeviceAnonymous UUID, generated and persisted by your app. Enables sticky rollout bucketing and the fleet dashboard. Optional but strongly recommended.

Responses:

  • 200 - update available; JSON manifest below.
  • 204 - up to date, no matching artifact, or this device is not in the rollout cohort yet. Either way: do nothing, check again later.
{
  "version": "1.5.0",
  "notes": "markdown release notes",
  "pub_date": "2026-07-12T10:00:00Z",
  "url": "https://your-storage/…/app-darwin-arm64.dmg",
  "sha512": "…",
  "signature": "…",
  "updateMode": "recommended",
  "minimumSupportedVersion": "1.2.0"
}

Version comparison is semver-aware (prereleases handled). Artifact matching: exact platform+arch first, then platform+universal, then platform-only.

Try it

# one device, currently on 1.0.0
curl -H "X-Relayer-Device: $(uuidgen)" \
  https://relayer-three.vercel.app/u/YOUR_APP_REF/stable/darwin/aarch64/1.0.0

# simulate a small fleet (each device = a distinct UUID)
for i in $(seq 1 10); do
  curl -s -o /dev/null -H "X-Relayer-Device: $(uuidgen)" \
    https://relayer-three.vercel.app/u/YOUR_APP_REF/stable/darwin/aarch64/1.0.0
done

Staged rollouts

Every release has a rollout percentage, controlled from the Releases tab (1 → 10 → 25 → 50 → 100 quick steps, or any value). Devices are bucketed deterministically - sha256(deviceId:releaseId) % 100 - so cohorts are sticky: a device offered 2.1.0 keeps being offered 2.1.0; a device outside the cohort keeps getting the previous release until you ramp.

Devices that don't send X-Relayer-Device can't be bucketed and sit out partial rollouts - they only receive fully-rolled-out (100%) releases.

Pause stops serving a release temporarily. Roll back withdraws it permanently - the fleet falls back to the newest remaining release on their next check. Rollbacks cannot be un-done by design; publish a fixed version.

Update policies

Per channel, set a minimum supported version. Devices reporting a version below it receive the update with "updateMode": "required" and the minimumSupportedVersion field - your app decides how to enforce it (block UI, force install, nag). Everything else gets your channel's default mode (optional or recommended).

Client loop (any language)

on schedule (e.g. every 6h + on launch):
  res = GET /u/APP/stable/{platform}/{arch}/{installed_version}
         with X-Relayer-Device: {stored_uuid}
  if res is 204: done
  if res is 200:
    verify sha512/signature after download
    if updateMode == "required": install now
    else: prompt or install per your UX

Ten lines in any runtime. If you ship Tauri or Electron, you don't even need that - see Adapters.

On this page