Skip to content

Back up a VPS

3 steps · Checked against the API code 3 November 2026

A guide does one task from start to finish. Every endpoint, with all its fields and cases, is in the API reference.

A backup is a full copy of the VPS disk. It is kept on separate backup storage. You start one with a single call and follow the job until it is done. To put a backup back, see Restore a VPS from a backup. For a quick undo point that lasts about a day, take a snapshot instead (Snapshot or backup).

  • An API key with the scope backup:vm. It covers every read on this page. A schedule needs write:vm as well. The requests use the key as $HOSTUP_API_KEY (Quickstart). Keys and scopes
  • The ID of the VPS, vps_…. List VPS instances if you don’t have it.
export VPS_ID="vps_…" # your VPS: List VPS instances

GET /api/v2/vps/{id}/backups lists the backups of the VPS, the slots they use and what you may do next.

GET /api/v2/vps/{id}/backups
curl "https://cloud.hostup.se/api/v2/vps/$VPS_ID/backups" \
-H "Authorization: Bearer $HOSTUP_API_KEY"
Response 200
{
"backups": [
{
"id": "bkp_01hxa3b4c5d6e7f8g9h0j1k2m3",
"createdAt": "2026-10-30T02:17:00.000Z",
"sizeGb": 12,
"backupType": "scheduled",
"note": "Scheduled daily backup",
"actions": {
"canRestore": { "allowed": true, "reason": null }
},
"…": "…"
}
],
"listing": { "status": "complete", "reason": null },
"quotaInfo": {
"used": 1,
"limit": 3,
"remaining": 2
},
"actions": {
"canCreateBackup": { "allowed": true, "reason": null },
"canRestore": { "allowed": true, "reason": null },
"…": "…"
},
"…": "…"
}
  • quotaInfo.limit is how many backups the VPS can keep. quotaInfo.remaining is how many slots are free. Manual and scheduled backups share these slots.
  • actions.canCreateBackup.allowed must be true. When it is false, reason says why. The usual reasons are full slots and a backup or restore that is already running. A VPS that isn’t active gets “This action requires an active service.”
  • When listing.status is unavailable, the list is empty because the backups could not be read right then. They are still there. Try again in a moment.

Do this only when quotaInfo.remaining is 0. Pick a backup you no longer need from backups. Keep its id.

export BACKUP_ID="bkp_…" # backups[].id of the backup to delete

Delete it with DELETE /api/v2/vps/{id}/backups/{backupId}. A deleted backup is gone for good.

DELETE /api/v2/vps/{id}/backups/{backupId}
curl -X DELETE "https://cloud.hostup.se/api/v2/vps/$VPS_ID/backups/$BACKUP_ID" \
-H "Authorization: Bearer $HOSTUP_API_KEY"

The answer is 204 with no body.

POST /api/v2/vps/{id}/backups starts the backup. The body is optional. note is stored with the backup. The API keeps its first 1,024 characters. The VPS keeps running while the backup is taken.

POST /api/v2/vps/{id}/backups
curl -X POST "https://cloud.hostup.se/api/v2/vps/$VPS_ID/backups" \
-H "Authorization: Bearer $HOSTUP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"note": "Before the PHP 8.4 upgrade"}'
Response 202
{
"operation": {
"status": "queued",
"jobId": "job_01hxa3b4c5d6e7f8g9h0j1k2m3",
"pollUrl": "/api/jobs/job_01hxa3b4c5d6e7f8g9h0j1k2m3"
}
}
export JOB_ID="job_…" # operation.jobId above

Poll the job until data.status is completed or failed. While it runs, it is waiting or running.

GET /api/jobs/{jobId}
curl "https://cloud.hostup.se/api/jobs/$JOB_ID" \
-H "Authorization: Bearer $HOSTUP_API_KEY"
Response 200
{
"success": true,
"data": {
"jobId": "job_01hxa3b4c5d6e7f8g9h0j1k2m3",
"type": "backup",
"status": "completed",
"progress": 100,
"…": "…"
},
"…": "…"
}

To poll until it ends, run the script from Jobs:

./wait-for-job.sh "/api/jobs/$JOB_ID"

If it ends failed, data.progressText says why when it is known. List the backups as in step 1 and start the backup again.

When it is completed, list the backups again as in step 1. The new one has backupType manual and your note. Without a note it says “Manual backup”. Its id (bkp_…) is what a restore takes.

Read the current schedule and its limits with GET /api/v2/vps/{id}/backup-schedules.

GET /api/v2/vps/{id}/backup-schedules
curl "https://cloud.hostup.se/api/v2/vps/$VPS_ID/backup-schedules" \
-H "Authorization: Bearer $HOSTUP_API_KEY"
Response 200
{
"schedules": [],
"settings": {
"autoDeleteOldest": true,
"…": "…"
},
"limits": {
"maxSchedules": 1,
"maxRetention": 3,
"availableScheduledSlots": 2,
"…": "…"
},
"actions": {
"canCreate": { "allowed": true, "reason": null },
"…": "…"
},
"…": "…"
}

A VPS has one schedule at most. limits.availableScheduledSlots is what the manual backups leave free.

Create the schedule with POST /api/v2/vps/{id}/backup-schedules.

POST /api/v2/vps/{id}/backup-schedules
curl -X POST "https://cloud.hostup.se/api/v2/vps/$VPS_ID/backup-schedules" \
-H "Authorization: Bearer $HOSTUP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"frequency": "daily",
"hour": 3,
"retentionCount": 3,
"enabled": true,
"name": "Nightly backup"
}'
Response 201
{
"id": "bks_01hxa3b4c5d6e7f8g9h0j1k2m3",
"name": "Nightly backup",
"frequency": "daily",
"time": "03:17",
"retentionCount": 3,
"enabled": true,
"nextRun": "2026-11-03T02:17:00.000Z",
"…": "…"
}
  • hour is Swedish time (Europe/Stockholm). Hostup sets the minute for each VPS. time shows the result.
  • weekly also needs dayOfWeek, 0 to 6 with 0 for Sunday. monthly needs dayOfMonth, 1 to 31. In a shorter month a day past its end runs on the last day.
  • retentionCount can’t be higher than limits.maxRetention. Each run keeps at most retentionCount scheduled backups. It never keeps more than limits.availableScheduledSlots. It deletes the oldest scheduled backups beyond that. With the example above (retentionCount 3, two free slots) the schedule keeps two. A schedule never deletes a manual backup.
  • When every slot is taken, a run goes ahead only if settings.autoDeleteOldest is true. It then deletes the oldest scheduled backup first. When manual backups fill every slot, scheduled runs are skipped. Change the setting with Update VPS backup settings.
  • Sending the same frequency again replaces the schedule. A different one answers 409 backup_schedule_limit_reached. Delete the old schedule first with Delete a VPS backup schedule.
  • Taking a backup creates no invoice. Hostup sends the account holder no e-mail about it.
  • A manual backup holds its slot until you delete it.
  • Restore a VPS from a backup puts a backup back onto the same VPS or onto a new Cloud VPS.
  • 403 forbidden with requiredScopes: the key lacks the scope named there (When a key is refused).
  • 403 forbidden without requiredScopes: detail does not say what is wrong. Two things cause it:
    • The VPS has used up its bandwidth allowance. Backups stay blocked until the usage resets or the limit is raised.
    • The backup you delete was already deleted or belongs to another VPS. List the backups again and pick an id from there.
  • 409 backup_slots_full: every backup slot of the VPS is used. detail gives the count. Delete a backup you no longer need (If every slot is used) and try again.
  • 409 backup_temporarily_locked on a delete: another operation is using the backup. Wait the seconds in the Retry-After header and try again.
  • 404 backup_not_found: no backup has that ID. Read the list right before you delete. Schedules delete old backups.

Next: Restore a VPS from a backup