Backups API
Schedule backup policies, run and inspect backups, stage and apply restores, and trigger backups by webhook.
The Backups API manages a project's backup policies (what to back up and on what schedule), the runs
they produce, and the restores that put a run's data back. It pairs with the
Backup Destinations API (where backups are stored) — in the dashboard this
is the project's Backups tab, and from the terminal it's the alaf server backup
command.
Base path & auth
All paths are relative to your instance, under /api — e.g. https://your-host/api/backup-runs/<id>.
Send a personal access token as a bearer header (Authorization: Bearer <token>), created with
alaf server token create. The dashboard uses your session cookie instead. See the
API overview for the full auth model.
The routes are split across a few prefixes: policy creation and listing are project-scoped
(/api/projects/:projectId/backup-policies), while an existing policy, run, or restore is addressed by
its own id (/api/backup-policies/:id, /api/backup-runs/:id, /api/backup-restores/:id). The inbound
POST /api/webhooks/backup trigger lives on its own unauthenticated prefix. Available on both self-hosted
and cloud instances; the project-scoped policy and run routes proxy to Alaf Server Cloud for cloud projects.
Endpoints
| Method & path | Permission | What it does |
|---|---|---|
GET /api/projects/:projectId/backup-policies | project:write | List a project's backup policies (schedules/retention). |
POST /api/projects/:projectId/backup-policies | project:write | Create a backup policy for a project. |
PATCH /api/backup-policies/:policyId | backup_destination:backup_policy:write | Update a policy. |
DELETE /api/backup-policies/:policyId | backup_destination:backup_policy:write | Delete a policy. |
POST /api/backup-policies/:policyId/run | backup_destination:backup_policy:write | Trigger the policy's backup now. |
GET /api/projects/:projectId/backup-runs | project:write | List a project's backup runs (history, status). |
GET /api/backup-runs/:runId | backup_destination:backup_run:read | Get one backup run's details/status. |
GET /api/backup-runs/:runId/stream | backup_destination:backup_run:read | SSE stream of a run's live progress. |
POST /api/backup-runs/:runId/protect | backup_destination:backup_run:write | Protect a run from retention pruning (or release it). |
POST /api/backup-runs/:runId/restore/prepare | backup_destination:backup_run:write | Stage a restore from a run; returns a confirmation token. |
POST /api/backup-restores/:restoreId/apply | backup_destination:backup_restore:write | Apply a staged restore (destructive). |
POST /api/backup-restores/:restoreId/cancel | backup_destination:backup_restore:write | Cancel a staged or in-flight restore. |
GET /api/backup-restores/:restoreId | backup_destination:backup_restore:read | Get one restore's status. |
GET /api/backup-restores/:restoreId/stream | backup_destination:backup_restore:read | SSE stream of a restore's live progress. |
POST /api/webhooks/backup | public | Trigger a backup from an inbound webhook (bearer token is the credential). |
Per-resource routes run a second permission check
Beyond the permission tag shown above, most :id routes run an in-handler check too. The policy update,
delete, and manual-run routes re-check the parent project (write to update or run, admin to
delete). Run and restore routes instead check the run or restore itself: read to view or stream, write to
protect a run, and admin for every destructive restore step (prepare, apply, cancel). A :id that isn't
in your organization returns 404.
Create a backup policy
A policy binds a project (optionally a single service) to a destination,
plus an optional schedule and retention rules. The request body is read inline (there is no TypeBox schema
file for this module); destinationId is the only required field.
POST /api/projects/:projectId/backup-policiesProp
Type
curl -X POST https://your-host/api/projects/proj_123/backup-policies \
-H "Authorization: Bearer $ALAFSERVER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"destinationId":"dst_abc","cronExpression":"0 3 * * *","retainCount":7}'# Same thing from the CLI:
alaf server backup policy create --project proj_123 --destination dst_abc \
--cron "0 3 * * *" --retain-count 7Update a policy
PATCH accepts only the allow-listed fields below — projectId, serviceId, and createdBy cannot be
changed, and the webhook token is controlled through the enableWebhook / rotateWebhookToken flags rather
than written directly. Unknown fields are dropped.
PATCH /api/backup-policies/:policyIdProp
Type
Trigger a backup manually
Kicks off a run for the policy immediately. Returns { data: { runId } } — follow it with the run stream.
POST /api/backup-policies/:policyId/runcurl -X POST https://your-host/api/backup-policies/bkp_abc/run \
-H "Authorization: Bearer $ALAFSERVER_TOKEN"# Trigger and stream to completion:
alaf server backup policy run bkp_abc --followProtect a run from retention
Retention prune drops runs past a policy's retainCount / retainDays. Lock a run to keep it, or release
the lock so it becomes eligible again.
POST /api/backup-runs/:runId/protectProp
Type
# Lock indefinitely, or release it:
alaf server backup run protect run_xyz
alaf server backup run protect run_xyz --releaseStage and apply a restore
Restoring is two steps. Prepare stages the restore and returns a one-time confirmationToken; apply
echoes that token back to actually run the (destructive) restore. This guards against accidental
re-submits.
POST /api/backup-runs/:runId/restore/prepareProp
Type
The response is { data: { restoreId, confirmationToken } }. Pass both to apply:
POST /api/backup-restores/:restoreId/applyProp
Type
# Prepare, then apply with the returned token:
alaf server backup run restore run_xyz
alaf server backup restore apply rst_123 --token <confirmationToken>Cancel a staged or in-flight restore with POST /api/backup-restores/:restoreId/cancel
(alaf server backup restore cancel rst_123).
Live progress (SSE)
Both runs and restores expose a Server-Sent Events channel that emits a snapshot event with the current
row immediately, then live transition / progress events, and a final complete event. Terminal
statuses are succeeded, failed, cancelled, and server_error; the stream closes once one is reached
(or right away if the row is already terminal).
GET /api/backup-runs/:runId/stream
GET /api/backup-restores/:restoreId/stream# The CLI's --follow flag consumes these streams:
alaf server backup run get run_xyz --follow
alaf server backup restore get rst_123 --followTrigger a backup by webhook
POST /api/webhooks/backup is the one unauthenticated route — the per-policy webhook token is the
credential, sent as a bearer header (enable it via enableWebhook on the policy). There is no request body.
On success it returns { data: { runId } }; every failure returns an opaque 404 so a probe can't tell a
bad token from a disabled policy. The route is rate-limited to blunt trigger-flood abuse.
POST /api/webhooks/backupcurl -X POST https://your-host/api/webhooks/backup \
-H "Authorization: Bearer $POLICY_WEBHOOK_TOKEN"Errors you might see
400 — invalid cron expression
createPolicy / updatePolicy validate the cron up front so an unparseable schedule can't silently disable
the policy. Fix the expression (e.g. 0 3 * * *) and retry.
400 — confirmationToken is required
Applying a restore without the exact token returned by restore/prepare is rejected. Re-run prepare to get
a fresh token if you've lost it.
404 on a per-resource route
The :id doesn't belong to your organization (or was deleted) — the same opaque 404 the webhook returns
for a bad token. List runs with GET /api/projects/:projectId/backup-runs to get valid IDs.
System API
Self-hosted instance administration — onboarding, SSH servers, component install, tunnels, filesystem browse, team-mode migration, and whole-instance data transfer.
Backup destinations API
Manage the storage targets (S3-compatible, SFTP, local, or another Alaf Server server) that backups are written to, and run a connectivity preflight.