Jobs
List backup and migration jobs, read run results, trigger runs.
List jobs
GET /v1/jobs returns backup jobs (bucket → bucket) and migration jobs as one list. Ids are strings like backup_12 or migration_3. A migration's source.type says where it reads from — ssh (one of your servers, over SFTP), azure (Blob container), or bucket (a managed bucket being copied down to a server); its destination is a bucket, or a server (in which case destination.bucketId is null).
{
"jobs": [
{
"id": "backup_12",
"type": "backup",
"name": "nightly-prod-backup",
"schedule": { "frequency": "daily", "hour": 2, "minute": 0, "dayOfWeek": null },
"enabled": true,
"status": "success",
"lastRunAt": "2026-07-16T02:00:04.000Z",
"lastRunResult": "Copied 1,204 objects (18.2 GB)",
"objectsCopied": 1204,
"bytesCopied": 19541237760,
"source": { "bucketId": 12, "prefix": null },
"destination": { "bucketId": 15, "prefix": "backups/prod/" },
"createdAt": "2026-04-11T09:20:33.000Z"
}
]
}A migration job's source looks like:
{
"id": "migration_3",
"type": "migration",
"source": { "type": "ssh", "sshServerId": 4, "bucketId": null, "path": "/var/exports" },
"destination": { "bucketId": 15, "prefix": "sftp-drops/" }
}GET /v1/jobs/{id} adds lastRunLog — the run's per-object events (capped at the most recent 200, with lastRunLogTruncated set when capped). A run can finish as success and still list per-object errors there, so check the log for skipped objects.
Trigger a run
Needs a read/write key. POST /v1/jobs/{id}/run queues a run of an existing job (a backup run writes objects to its destination, so it counts as a change). Returns 202 when accepted, 409 with code ALREADY_RUNNING if the job is mid-run.
curl -X POST https://bucketpilot.io/api/v1/jobs/backup_12/run \
-H "Authorization: Bearer $BUCKETPILOT_KEY"The run lands in the activity feed attributed to the API key, and job status/results are visible on the next GET /v1/jobs/{id}.
Pause or cancel a run
Needs a read/write key. POST /v1/jobs/{id}/pause and POST /v1/jobs/{id}/cancel stop a running job. The difference is how the run is recorded — paused reads as "to be continued", cancelled as deliberately stopped. Either way nothing is lost: copies skip objects that already exist at the destination, so the next run picks up where this one left off. Both return 409 with code NOT_RUNNING if the job isn't currently running.
curl -X POST https://bucketpilot.io/api/v1/jobs/backup_12/cancel \
-H "Authorization: Bearer $BUCKETPILOT_KEY"The stop takes effect within a few seconds (the executing worker picks up the flag at its next progress beat).