Publishing releases
Publish from the API, from CI, or automatically from GitHub releases.
Via the CLI
The fastest path from CI:
npx relayerctl releases create --app YOUR_APP_REF --channel stable \
--version 1.4.2 --notes-file CHANGELOG.md \
--artifact platform=windows,arch=x86_64,url=https://your-storage/setup.exeSee the CLI guide for auth, artifacts and push-mode commands.
Promote a GitHub release
With GitHub connected (see the Changelog guide for setup), the Releases tab has Promote from GitHub: pick one tagged release, choose the channel and starting rollout percentage, and its assets become artifacts automatically (URLs point at the GitHub assets - decisions, not bytes). Releases are never created from GitHub automatically; promoting is always a deliberate act.
Hosted changelog page
Every app gets a shareable public changelog at
https://www.relayercli.com/changelog/your-app (pick the slug in app settings; the
immutable ref works there too): your published changelog entries on a
timeline with per-entry detail pages. See the
Changelog guide for generating entries from GitHub
activity. The machine-readable release feeds (RSS and JSON, per channel)
stay under /feed/... and track published releases: rollbacks disappear
from them automatically.
Via the API
curl -X POST https://www.relayercli.com/api/v1/releases \
-H "Authorization: Bearer rl_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"app": "YOUR_APP_REF",
"channel": "stable",
"version": "1.4.2",
"notes": "markdown release notes",
"artifacts": [{
"platform": "windows",
"arch": "x86_64",
"url": "https://your-storage/…/setup.exe",
"sha512": "optional integrity hash",
"size": 48234496,
"signature": "optional (e.g. Tauri minisign)"
}]
}'Works from any CI. Versions are unique per app+channel (409 on duplicates, so retried CI jobs are safe). See the API reference for all endpoints.
Manage serving via the API
Everything the Releases tab does to a shipped release works over
PATCH /api/v1/releases too - ramp, pause, resume, roll back, target:
# ramp the rollout to 50%
curl -X PATCH https://www.relayercli.com/api/v1/releases \
-H "Authorization: Bearer rl_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "app": "YOUR_APP_REF", "channel": "stable", "version": "1.4.2", "rollout": 50 }'
# target the canary ring, then later roll back
curl -X PATCH ... -d '{ "app": "...", "channel": "stable", "version": "1.5.0",
"targets": { "matchLabels": { "tier": ["canary"] } } }'
curl -X PATCH ... -d '{ "app": "...", "channel": "stable", "version": "1.5.0",
"status": "rolled_back" }'The API enforces the exact same invariants as the dashboard, because they
share the same code: once a release has been offered, the rollout
percentage only increases and targeting only broadens (both answer 422
otherwise - pause to stop, roll back to pull), and a rolled-back release
can never be re-served (409). Every change lands in the audit log with
the API key as the actor.
Via GitHub releases
Keep your existing flow - gh release create v2.1.0 ./dist/* - and let the
webhook do the rest.
Setup: on your app's Settings tab, click Connect under GitHub
releases, then in your repo: Settings → Webhooks → Add webhook → paste the
payload URL and secret → content type application/json → select only the
Releases event.
Behavior:
- Pre-releases land on
beta, normal releases onstable. - The tag (minus a leading
v) becomes the version; the release body becomes the notes. - Assets are classified by filename into platform/arch (works with
electron-builder, Tauri, GoReleaser and common naming schemes); checksum
and metadata files (
.sig,.yml,SHA256SUMS, …) are excluded. - Drafts are ignored; GitHub's retry deliveries are answered as duplicates, never double-ingested.
- Every delivery is HMAC-verified (SHA-256, timing-safe).
Test without a repo
Any correctly-signed POST is a valid delivery - sign one yourself with your
webhook secret and openssl:
SECRET="<webhookSecret>" # app Settings → GitHub releases
BODY='{"action":"published","repository":{"full_name":"you/app"},"release":{"id":1,"tag_name":"v1.2.0","name":"v1.2.0","body":"## Notes","draft":false,"prerelease":false,"html_url":"https://github.com/you/app/releases/tag/v1.2.0","assets":[{"name":"myapp-1.2.0-darwin-aarch64.dmg","browser_download_url":"https://example.com/myapp-1.2.0.dmg","size":52428800,"content_type":"application/octet-stream"}]}}'
SIG="sha256=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')"
curl -X POST <payload-url> \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: release" \
-H "X-Hub-Signature-256: $SIG" \
-d "$BODY"