Backups
Nightly backups as a paid add-on. Turn them on, run one now, browse restore points, restore files or the whole server, and download archives.
Backups are an add-on for a server. Once turned on, the server is backed up every night at the hour you choose, older backups are kept according to the plan, and you can restore single files, restore the whole server, or download files as an archive.
The add-on has its own billing period (monthly or yearly), separate from the server's. It is charged to the wallet up front.
Backups are available for Linux servers that have finished provisioning. Times in this API are in WIB (UTC+7): the nightly hour, and the daily limits that reset at midnight WIB.
While a backup, a restore or a backup setup is queued or running, other changes to the server (power, reinstall, snapshots, firewall) answer 409 VPS_BUSY.
Backup plans
/backup/plansNote the path: https://api.helipod.io/api/backup/plans, not under /vps.
curl https://api.helipod.io/api/backup/plans \
-H "Authorization: Bearer hel_your_key"{
"success": true,
"data": [
{
"code": "basic",
"name": "Backup Basic",
"quotaBytes": 21474836480,
"priceMonthly": 15000,
"priceYearly": 150000,
"keepDaily": 7,
"keepWeekly": 4,
"keepMonthly": 3
}
]
}| Field | Description |
|---|---|
code | Plan code. Send it as planCode. |
name | Display name. |
quotaBytes | Storage allowed for all backups of the server, after compression and deduplication. |
priceMonthly, priceYearly | Price of one month or one year, in Rupiah. |
keepDaily, keepWeekly, keepMonthly | How many daily, weekly and monthly restore points are kept. |
Backup status
/vps/:id/backupcurl https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup \
-H "Authorization: Bearer hel_your_key"{
"success": true,
"data": {
"id": "3c2b1a09-8f7e-4d6c-b5a4-938271605f4e",
"status": "active",
"eligible": true,
"reason": null,
"plan": { "code": "basic", "name": "Backup Basic", "quotaBytes": 21474836480, "priceMonthly": 15000 },
"nextPlan": null,
"period": { "start": "2026-10-16T09:00:00.000Z", "end": "2026-11-16T09:00:00.000Z", "months": 1 },
"price": 15000,
"autoRenew": true,
"graceUntil": null,
"purgeAfter": null,
"storage": {
"usedBytes": 3221225472,
"quotaBytes": 21474836480,
"protectedBytes": 0,
"measuredAt": "2026-10-17T19:40:00.000Z",
"historyReduced": false
},
"lastBackup": { "at": "2026-10-17T19:31:05.000Z", "status": "ok", "error": null },
"nextRunAt": "2026-10-18T19:17:00.000Z",
"scheduleHour": 2,
"manualRunsLeft": 3,
"activeRun": null
}
}| Field | Description |
|---|---|
status | See Add-on statuses. |
eligible, reason | Whether the server can use backups, and why not. |
plan, nextPlan | Current plan, and a smaller plan scheduled for the next renewal. |
period | Current billing period and its length in months (1 or 12). |
price | Price of one full period. |
autoRenew | Whether the add-on renews itself from the wallet at period.end. |
graceUntil | End of the grace period after a failed renewal. |
purgeAfter | When the stored backups will be deleted, after the add-on ended. |
storage | Space used, the quota, and whether older history was trimmed to fit (historyReduced). |
lastBackup | Time and outcome (ok or failed) of the last backup. |
nextRunAt | Next scheduled backup, or null when backups are not running. |
scheduleHour | Hour (0 to 23, WIB) the nightly backup starts. The exact minute within that hour is fixed per server. |
manualRunsLeft | Manual backups you can still start today. |
activeRun | The backup, restore or setup holding the server right now, with kind, status and since. |
Add-on statuses
| Status | Meaning |
|---|---|
setting_up | Backups are being prepared. |
active | Backups run every night. |
over_quota | Storage is over the quota. Backups still run, and older history is trimmed. |
paused_quota | Storage is far over the quota. Backups are paused until you upgrade the plan. |
grace | A renewal failed. For 7 days no new backups run, but you can still restore and download. |
expired | The period ended without renewal. Restores and downloads work until purgeAfter. |
cancelled | Ended after auto-renew was switched off. Restores and downloads work until purgeAfter. |
setup_failed | The add-on could not be set up. |
Stored backups are deleted 7 days after the add-on expires or is cancelled.
Turn backups on
/vps/:id/backupcharges your walletProp
Type
curl -X POST https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup \
-H "Authorization: Bearer hel_your_key" \
-H "Content-Type: application/json" \
-d '{ "planCode": "basic", "months": 1, "scheduleHour": 2 }'Returns the backup status with status: "active".
- The server must be an eligible Linux server and
running. - The wallet is charged for the first period at once. Without enough balance the call answers
402 INSUFFICIENT_BALANCEand nothing is created. - Preparation happens in the background before the first scheduled backup. The first backup runs at the next
scheduleHour; start one earlier with run now. - A server can have one add-on at a time: a second call answers
409 ALREADY_SUBSCRIBED.
Change the plan, hour or auto-renew
/vps/:id/backupcharges your walletProp
Type
curl -X PATCH https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup \
-H "Authorization: Bearer hel_your_key" \
-H "Content-Type: application/json" \
-d '{ "planCode": "pro" }'Returns the updated backup status. Send only the fields you want to change.
- Larger plan: applies at once. The wallet is charged the price difference for the time left in the current period (rounded up to whole Rupiah), and a paused add-on resumes.
- Smaller plan: scheduled for the next renewal and shown as
nextPlan; nothing is charged. Refused with409 OVER_NEW_QUOTAif your backups already use more than the smaller plan allows. - Same plan as now: cancels a scheduled downgrade.
Cancel
/vps/:id/backupcurl -X DELETE https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup \
-H "Authorization: Bearer hel_your_key"Returns the backup status with autoRenew: false. Backups keep running until period.end; there is no refund. Switch it back on with PATCH and { "autoRenew": true } before the period ends.
Run a backup now
/vps/:id/backup/runcurl -X POST https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup/run \
-H "Authorization: Bearer hel_your_key"{ "success": true, "data": { "runId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" } }- The add-on must be
activeorover_quota(409 NOT_RUNNABLEotherwise) and the serverrunning(409 VPS_NOT_RUNNING). - Only one backup or restore at a time (
409 BUSY), and not while the server itself is busy (409 VPS_BUSY). - Each plan allows a few manual backups per day (
manualRunsLeftin the status). Over the limit:429 LIMIT.
Follow the run in backup runs.
Backup runs
/vps/:id/backup/runscurl https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup/runs \
-H "Authorization: Bearer hel_your_key"{
"success": true,
"data": [
{
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"kind": "backup",
"trigger": "manual",
"status": "ok",
"skipReason": null,
"error": null,
"bytesProcessed": 4831838208,
"bytesAdded": 52428800,
"createdAt": "2026-10-17T03:10:00.000Z",
"startedAt": "2026-10-17T03:10:02.000Z",
"finishedAt": "2026-10-17T03:14:40.000Z"
}
]
}| Field | Values |
|---|---|
kind | setup, backup, restore_files, restore_full, prune, download, purge |
trigger | schedule, manual, pre_reinstall, admin, system |
status | queued, running, ok, failed, skipped |
error | Reason, when status is failed. |
Returns an empty list when the server has no add-on.
Restore points
/vps/:id/backup/pointscurl https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup/points \
-H "Authorization: Bearer hel_your_key"{
"success": true,
"data": [
{
"id": "f0e1d2c3-b4a5-4968-8776-655443322110",
"takenAt": "2026-10-17T19:31:05.000Z",
"kind": "daily",
"sizeAdded": 52428800,
"filesTotal": 48213
}
]
}kind is daily, weekly (taken on a Sunday), monthly (taken on the 1st), manual, or pre_reinstall (taken automatically before a full restore). sizeAdded is the new data the point added, in bytes.
Browse a restore point
/vps/:id/backup/points/:pointId/filesProp
Type
curl "https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup/points/f0e1d2c3-b4a5-4968-8776-655443322110/files?path=/etc/nginx" \
-H "Authorization: Bearer hel_your_key"{
"success": true,
"data": {
"path": "/etc/nginx",
"entries": [
{ "name": "nginx.conf", "path": "/etc/nginx/nginx.conf", "type": "file", "size": 1482, "mtime": "2026-09-30T04:12:00.000Z" },
{ "name": "sites-enabled", "path": "/etc/nginx/sites-enabled", "type": "dir", "size": 0, "mtime": "2026-10-01T02:00:00.000Z" }
]
}
}type is file, dir or symlink. The server itself is not touched. The answer can take several seconds; if it does not come within about 20 seconds the call answers 400 with a message to try again.
Restore
/vps/:id/backup/points/:pointId/restoreProp
Type
curl -X POST https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup/points/f0e1d2c3-b4a5-4968-8776-655443322110/restore \
-H "Authorization: Bearer hel_your_key" \
-H "Content-Type: application/json" \
-d '{ "mode": "files", "paths": ["/etc/nginx", "/var/www/html/index.php"], "target": "folder" }'{ "success": true, "data": { "runId": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e" } }Follow runId in backup runs (kind restore_files or restore_full).
- The server must be
running(409 VPS_NOT_RUNNING), with no other backup or restore in progress (409 BUSY) and not busy itself (409 VPS_BUSY). - A full restore reinstalls the server's current operating system, restores every file from the point and restarts the server. Anything written since the point is lost. When backups are active, a backup of the current state (
pre_reinstall) is taken first, so you can go back; the restore then goes ahead whatever that backup's outcome. - Restores also work in the
grace,expiredandcancelledstatuses, until the backups are deleted.
Download files
/vps/:id/backup/points/:pointId/downloadProp
Type
curl -X POST https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup/points/f0e1d2c3-b4a5-4968-8776-655443322110/download \
-H "Authorization: Bearer hel_your_key" \
-H "Content-Type: application/json" \
-d '{ "paths": ["/var/www"] }'{
"success": true,
"data": {
"id": "c3d4e5f6-a7b8-4c9d-8e0f-2a3b4c5d6e7f",
"status": "queued",
"sizeBytes": null,
"expiresAt": null,
"url": null,
"error": null
}
}The archive (.tar.gz) is built in the background, without touching the server. Each plan allows a few downloads per day; over the limit the call answers 429 LIMIT.
Download status
/vps/:id/backup/downloads/:downloadIdcurl https://api.helipod.io/api/vps/1f757fd5-98d1-490a-81a0-58b5798a5815/backup/downloads/c3d4e5f6-a7b8-4c9d-8e0f-2a3b4c5d6e7f \
-H "Authorization: Bearer hel_your_key"{
"success": true,
"data": {
"id": "c3d4e5f6-a7b8-4c9d-8e0f-2a3b4c5d6e7f",
"status": "ready",
"sizeBytes": 734003200,
"expiresAt": "2026-10-18T10:20:00.000Z",
"url": "https://download.example/archive.tar.gz?signature=...",
"error": null
}
}status moves from queued to building to ready (or failed, with error). Poll every few seconds. url is a signed link, present only while the status is ready; it works until expiresAt (about 24 hours), after which the status reads expired.
Errors
| Status | Code | When |
|---|---|---|
404 | INSTANCE_NOT_FOUND | No server with this id within the key's reach: unknown, another account's, or outside the key's project. |
404 | NOT_FOUND | Unknown restore point or download. |
400 | NOT_ELIGIBLE | The server cannot use backups (error says why, for example not Linux or not provisioned). |
400 / 409 | VPS_NOT_RUNNING | The server must be running. |
409 | AGENT_OFFLINE | The server's management agent does not answer. Restart the server and try again. |
409 | NODE_NOT_READY | Backups are not available on this server yet. |
404 | PLAN_NOT_FOUND | Unknown or retired planCode. |
409 | ALREADY_SUBSCRIBED | The server already has the add-on. |
409 | BONUS_IN_USE | A bundled backup bonus for this server is already being claimed. |
402 | INSUFFICIENT_BALANCE | The wallet cannot cover the charge. |
404 | NOT_SUBSCRIBED | No add-on, or no backups to read yet. |
409 | OVER_NEW_QUOTA | The smaller plan cannot hold your current backups. |
409 | NOT_RUNNABLE | The add-on is not in a status that runs backups. |
409 | BUSY | Another backup or restore is in progress. |
409 | VPS_BUSY | The server is busy with another action. |
429 | LIMIT | Daily manual backup or download limit reached. |
409 | NO_BLUEPRINT | The server's operating system cannot be determined for a full restore. |
503 | BACKUP_NOT_CONFIGURED | Backups are temporarily unavailable. |
400 / 404 / 409 | BACKUP_ERROR | Any other backup rule, for example an invalid path or too many paths. Read error. |