Workers
Provisioning and rotating worker credentials.
View as MarkdownA worker is a credential, not a machine. These endpoints manage the credential; the process that uses it is installed separately.
workers:* is human-only, so a machine key cannot provision or rotate a worker.
Create
curl -fsS -X POST https://api.saved.sh/v1/workers \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name": "prod-worker-1"}'{
"id": "0f2c9a1e-...",
"name": "prod-worker-1",
"secret": "sk_live_...",
"created_at": "2026-08-08T09:14:02Z",
"updated_at": "2026-08-08T09:14:02Z"
}Permission: workers:write. Returns 201.
secret appears here and nowhere else. It goes into that machine's config.yaml as
token. If you lose it, rotate rather than deleting the worker.
The key is created carrying exactly artifacts:upload and artifacts:confirm. You cannot
choose its permissions, and there is no field to try.
List
curl -fsS https://api.saved.sh/v1/workers -H "Authorization: Bearer $TOKEN"{
"data": [
{
"id": "0f2c9a1e-...",
"name": "prod-worker-1",
"instances": 1,
"last_seen": "2026-08-08T09:41:12Z",
"created_at": "2026-08-08T09:14:02Z",
"updated_at": "2026-08-08T09:14:02Z"
}
],
"next_cursor": null
}Permission: workers:read.
Presence
instances and last_seen are read live from the polling connections, not from a
heartbeat we store.
Connected is trustworthy; disconnected lags. Poller records expire on a TTL, so a worker that died thirty seconds ago can still report as present for a few minutes. Never render this as a definite red light: show "last seen", and treat a stale value as unknown rather than down.
instances above 1 is worth investigating. Several processes may share one credential and all
poll the same queue, but a run's steps hand each other a path to a local file, so splitting
them across machines breaks the run. See
one process per credential.
instances is null when presence could not be read, which is not the same as 0.
Get
curl -fsS "https://api.saved.sh/v1/workers/$WORKER_ID" -H "Authorization: Bearer $TOKEN"Permission: workers:read. Presence fields are not included on the single-worker read.
Rotate
curl -fsS -X POST "https://api.saved.sh/v1/workers/$WORKER_ID/rotate" \
-H "Authorization: Bearer $TOKEN"{ "id": "0f2c9a1e-...", "name": "prod-worker-1", "secret": "sk_live_...", "...": "..." }Permission: workers:write.
The worker ID is unchanged, so every backup assigned to it keeps working once the new key is deployed. This is the answer to a leaked key, a decommissioned host, or ordinary hygiene.
The old key is revoked the moment the new one is issued. Any process still holding it stops
polling, so expect a short gap: rotate, write the new key into config.yaml, restart the
worker. A run already in flight is retried when the worker returns, because the run belongs
to the queue rather than the connection.
Delete
curl -fsS -X DELETE "https://api.saved.sh/v1/workers/$WORKER_ID" -H "Authorization: Bearer $TOKEN"Permission: workers:revoke, which is a separate permission from workers:write. Returns
204.
Deletion revokes the key permanently. Backups assigned to the worker are left with nowhere to run: their scheduled runs queue on a task queue nothing polls, silently.
| Rotate | Delete | |
|---|---|---|
| Worker ID | Unchanged | Gone |
| Assigned backups | Keep working | Have nowhere to run |
| Reversible | No new key needed | No |
Reassign or pause those backups before deleting the worker they point at.
What the credential authorizes
| Permission | Allows |
|---|---|
artifacts:upload | Request a presigned upload URL for one of its own runs |
artifacts:confirm | Report the checksum, size and filename of what it uploaded |
That is the entire surface. A worker key cannot read backup definitions, list artifacts, download anything, or manage workers. On the orchestration side it is bound to one namespace and one task queue, its own.
artifacts:confirm is refused on an ordinary API key, which makes it the worker/automation
discriminator.
Quotas
| Plan | Workers per workspace |
|---|---|
| Trial | 1 |
| Paid | 10 |