API reference · Hubtask API 0.1.0
backup
GET /backup-targets
List the backup targets
Responses
200The targets403An error per RFC 9457 Problem
curl -X GET "$HUBTASK_URL/backup-targets" \ -H "Authorization: Bearer $HUBTASK_TOKEN" POST /backup-targets
Create a backup target
Requires instance administrator rights (tenant-owned targets only when enabled). Credentials are stored encrypted and never returned. An unencrypted backup and the FTP protocol both require insecure_acknowledged: true. Auditable.
Request body application/json — BackupTargetCreate
Responses
201Created BackupTarget400An error per RFC 9457 Problem403An error per RFC 9457 Problem
curl -X POST "$HUBTASK_URL/backup-targets" \ -H "Authorization: Bearer $HUBTASK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "kind": "LOCAL", "config": {}, "credentials": {}, "encryption_mode": "AES256_GCM", "encryption_passphrase": "string", "insecure_acknowledged": false}' DELETE /backup-targets/{targetId}
Remove a backup target from the workspace's configuration
Removes the target and its sealed credential. Nothing at the target is touched. The rule that Hubtask never deletes a file it did not write applies at least as strongly to the files it did write: the archives stay where they are, and an operator who wants them gone removes them at the target. A target a schedule still names is refused with 409 and the schedules named in the problem document. Deleting one silently would disarm a backup that runs every night, and the disarming would be discovered by whoever needed the archive. Deleting one that is not there is not an error. Auditable.
Path parameters
Responses
204Removed4XXAn error per RFC 9457 Problem
curl -X DELETE "$HUBTASK_URL/backup-targets/{targetId}" \ -H "Authorization: Bearer $HUBTASK_TOKEN" POST /backup-targets/{targetId}:test
Test the connection to the target
A write/read/delete probe. Runs through the GuardedClient (SSRF protection).
Path parameters
Responses
200The result BackupTargetProbe4XXAn error per RFC 9457 Problem
curl -X POST "$HUBTASK_URL/backup-targets/{targetId}:test" \ -H "Authorization: Bearer $HUBTASK_TOKEN" GET /backup-targets/{targetId}/backups
List the backups present at the target
Reads the manifests at the target, not from the database. That means the listing works even after a total loss, as long as the target credentials are known.
It answers the workspace's own archives. A credential carrying admin:tenants - the installation operator's - also sees archives of workspaces this installation does not hold, such as an export written by another installation, which a NEW_TENANT restore takes; never an archive of another workspace that exists here.
Path parameters
Query parameters
Responses
200The archives at the target403An error per RFC 9457 Problem
curl -X GET "$HUBTASK_URL/backup-targets/{targetId}/backups" \ -H "Authorization: Bearer $HUBTASK_TOKEN" GET /backup-schedules
The schedules the workspace has
What runs on its own, and when it next will. Needs the permission that manages structure, or the auditor's read-only configuration permission - a schedule is what a workspace has decided will leave it every night, which is exactly what an auditor reads. next_run_at is absent for a schedule that is switched off and for one whose recurrence is exhausted. The second is not an error: the rule may be perfectly good and simply spent, and the schedule stays visible and editable rather than disappearing.
Responses
200The schedules4XXAn error per RFC 9457 Problem
curl -X GET "$HUBTASK_URL/backup-schedules" \ -H "Authorization: Bearer $HUBTASK_TOKEN" POST /backup-schedules
Create a backup schedule
RRULE-based (RFC 5545), with generational retention and a min_keep floor.
Request body application/json — BackupSchedule
Responses
201Created BackupSchedule400An error per RFC 9457 Problem
curl -X POST "$HUBTASK_URL/backup-schedules" \ -H "Authorization: Bearer $HUBTASK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c", "target_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c", "scope": {}, "rrule": "FREQ=DAILY;BYHOUR=3;BYMINUTE=0", "timezone": "UTC", "mode": "INCREMENTAL", "full_rrule": "FREQ=WEEKLY;BYDAY=SU", "include_media": true, "include_audit": true, "trial_restore": true, "retention": {}, "notify_on": [ "FAILURE" ], "enabled": true, "next_run_at": "2026-09-16T10:00:00Z"}' PATCH /backup-schedules/{scheduleId}
Change a schedule, or switch it off
Merge-patch: an absent key changes nothing. enabled is the field that matters most and the reason a DELETE is not the only answer - switching a schedule off keeps what somebody worked out about hours, zones and generations, and turning it back on costs one request rather than a form filled in again. Changing the rule, the zone or the switch recomputes when it is next owed, here rather than on every read. A rule with no occurrence inside a year stores no next moment and is not refused, for the reason creating one is not. The scope does not move: a schedule that changed from one hub to another would be a different schedule wearing an old identifier, and the archives already at the target would disagree with it. Auditable.
Path parameters
Headers
Request body application/merge-patch+json — BackupScheduleUpdate
Responses
200Changed BackupSchedule4XXAn error per RFC 9457 Problem
curl -X PATCH "$HUBTASK_URL/backup-schedules/{scheduleId}" \ -H "Authorization: Bearer $HUBTASK_TOKEN" \ -H 'If-Match: "<the ETag you read>"' \ -H "Content-Type: application/merge-patch+json" \ -d '{ "rrule": "FREQ=DAILY;BYHOUR=3;BYMINUTE=0", "timezone": "string", "mode": "FULL", "full_rrule": "string", "include_media": true, "include_audit": true, "trial_restore": true, "retention": {}, "notify_on": [ "FAILURE" ], "enabled": true}' DELETE /backup-schedules/{scheduleId}
Remove a schedule
The schedule stops existing and nothing else changes: the archives it produced stay at the target, and the runs it started stay in the log. Removing one that is not there is not an error. Auditable. Switching a schedule off is usually the right operation and this one is not - PATCH with enabled: false keeps the rule for the night somebody wants it back.
Path parameters
Responses
204Removed4XXAn error per RFC 9457 Problem
curl -X DELETE "$HUBTASK_URL/backup-schedules/{scheduleId}" \ -H "Authorization: Bearer $HUBTASK_TOKEN" POST /backups
Start a backup immediately
The run is a job: this answers a JobRef whose result_url is the backup run, and the run's id is also the archive's id in the manifest at the target. One identifier for both, so that a caller who has a run has an archive and needs no mapping in between.
Request body application/json — BackupStart
Responses
curl -X POST "$HUBTASK_URL/backups" \ -H "Authorization: Bearer $HUBTASK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "target_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c", "mode": "FULL", "include_media": true, "include_audit": true}' GET /backups/{backupId}
What one backup run did
The resource a started backup's result_url points at: what was written, where, how much of it, and whether it has been verified since. It is read from the database rather than from the target, so it is what a caller polls while the run is still going - /backup-targets/{targetId}/backups is the reading that survives losing the database.
Path parameters
curl -X GET "$HUBTASK_URL/backups/{backupId}" \ -H "Authorization: Bearer $HUBTASK_TOKEN" POST /backups/{backupId}:verify
Verify an archive at the target
Check the checksums and decryptability without restoring. The result is recorded on the run as verified_at and verify_ok.
Path parameters
Responses
curl -X POST "$HUBTASK_URL/backups/{backupId}:verify" \ -H "Authorization: Bearer $HUBTASK_TOKEN" POST /restores
Start a restore
A dry run (dry_run: true) with a report by default. Destructive modes (REPLACE_TENANT, INSTANCE) additionally require step-up authentication and the tenant name typed into confirmation. NEW_TENANT and INSTANCE create a workspace or cross all of them, so they are the installation operator's: the credential needs the admin:tenants scope as well, and is refused with access.insufficient_scope without it. A restore fires no automation, sends no notifications, and restores no tokens.
Request body application/json — RestoreRequest
Responses
Codes this operation names
curl -X POST "$HUBTASK_URL/restores" \ -H "Authorization: Bearer $HUBTASK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "target_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c", "archive_id": "string", "mode": "INSPECT", "target_tenant_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c", "conflict_rule": "SKIP", "selection": {}, "decryption_passphrase": "string", "dry_run": true, "create_safety_backup": true, "confirmation": "string", "step_up_token": "string"}' GET /restores/{restoreId}
What one restore did, or is about to do
The resource a started restore's result_url points at. It carries the report of the dry run - how many objects are new, overwritten, skipped and in conflict - which is what a caller reads before asking for the same restore without dry_run. It also names the safety copy taken before a destructive mode, so that the way back is a run identifier rather than a search at the target.
Path parameters
Responses
200The run RestoreRun403An error per RFC 9457 Problem404An error per RFC 9457 Problem
curl -X GET "$HUBTASK_URL/restores/{restoreId}" \ -H "Authorization: Bearer $HUBTASK_TOKEN"