Backups
A backup is a full export of the platform database, taken together with an archive of the files users have uploaded (such as documents and profile images) and an archive of the Networks vault, where saved networks and their runs are kept. A part that is not present on the installation is skipped. Treat every backup as highly sensitive: it contains all of the platform's data, including user accounts and the stored credentials of connected systems.
Backups are created automatically at the interval set in the deployment configuration, and on demand with Create a backup. Each backup is identified by the UTC time it started, in the form 20260911T020003Z. After each backup, backups older than the retention period are deleted. Retrieve backup status shows the schedule and retention in effect.
Restoring is destructive; read Restore a backup before you use it. Backups can't be listed, started, downloaded, or restored through the API while the installation's licence is restricted (after it expires, for example): these calls return 402 until a valid licence is installed.
Administrator access. Every endpoint on this page requires an administrator account.
- GET /admin/backups/status Retrieve backup status
- GET /admin/backups List backups
- POST /admin/backups Create a backup
- GET /admin/backups/{backup_id} Retrieve a backup
- GET /admin/backups/{backup_id}/download Download a backup
- POST /admin/backups/{backup_id}/restore Restore a backup
- DEL /admin/backups/{backup_id} Delete a backup
Paths are relative to /api
The backup object
One backup and the result of each of its parts.
Attributes
-
idstringIdentifier of the backup: the UTC time it started, as
YYYYMMDDTHHMMSSZ. -
created_atstringWhen the backup started, in ISO 8601 with a UTC offset.
-
triggerstringmanualfor a backup requested with Create a backup,scheduledfor one created by the schedule. -
okbooleanWhether every component succeeded or was skipped.
-
errornullable stringWhy the backup failed, or
null. -
archive_size_bytesintegerSize of the downloadable archive, in bytes.
-
componentsobjectResult for each part of the backup, keyed by
postgres(the database export),uploads(uploaded files), andvault(the Networks vault). Each value has the fields below.Show child attributes Hide child attributes
-
namestringThe component's key.
-
size_bytesintegerSize of the component within the backup, in bytes.
-
okbooleanWhether the component was backed up. A skipped component also reports
true. -
skippedbooleantruewhen the component's source is not present on this installation. -
errornullable stringWhy the component failed or was skipped, or
null.
-
{
"id": "20260911T020003Z",
"created_at": "2026-09-11T02:00:03.418552+00:00",
"trigger": "scheduled",
"components": {
"postgres": {
"name": "postgres",
"size_bytes": 48213775,
"ok": true,
"skipped": false,
"error": null
},
"uploads": {
"name": "uploads",
"size_bytes": 231904512,
"ok": true,
"skipped": false,
"error": null
},
"vault": {
"name": "vault",
"size_bytes": 18350421,
"ok": true,
"skipped": false,
"error": null
}
},
"archive_size_bytes": 297431040,
"ok": true,
"error": null
} Retrieve backup status
GET /api/admin/backups/status
Returns the backup schedule, retention, and most recent backup.
Returns the backup configuration in effect and a summary of the existing backups. The schedule, its interval, the retention period, and whether the database can be restored through the API are set in the deployment configuration and can't be changed through the API.
- Authentication
- Bearer token How it works
- Permission
- Requires an administrator account.
Parameters
No parameters.
Returns
Returns the backup status in data: enabled (scheduled backups on or off), interval_seconds (interval between scheduled backups; values below 300 are treated as 300), retention_days (backups older than this are deleted; values below 1 are treated as 1), uploads_present and vault_present (whether those parts exist and are therefore backed up), running (a best-effort flag that is true while a backup requested through the API is being created; scheduled backups are not reflected), last_run_at (when the most recent backup attempt, manual or scheduled, started, or null), last_backup (the newest backup object, or null), backup_count, and allow_online_restore (whether the database component can be restored with Restore a backup).
Errors
- 403 The caller is not an administrator.
- 500 The backup status could not be read.
curl "$VDF_BASE_URL/api/admin/backups/status" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/admin/backups/status`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/api/admin/backups/status",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"data": {
"enabled": true,
"interval_seconds": 86400,
"retention_days": 14,
"uploads_present": true,
"vault_present": true,
"running": false,
"last_run_at": "2026-09-11T02:00:03.418552+00:00",
"last_backup": {
"id": "20260911T020003Z",
"created_at": "2026-09-11T02:00:03.418552+00:00",
"trigger": "scheduled",
"components": {
"postgres": {
"name": "postgres",
"size_bytes": 48213775,
"ok": true,
"skipped": false,
"error": null
},
"uploads": {
"name": "uploads",
"size_bytes": 231904512,
"ok": true,
"skipped": false,
"error": null
},
"vault": {
"name": "vault",
"size_bytes": 18350421,
"ok": true,
"skipped": false,
"error": null
}
},
"archive_size_bytes": 297431040,
"ok": true,
"error": null
},
"backup_count": 14,
"allow_online_restore": false
}
} List backups
GET /api/admin/backups
Returns every available backup, newest first.
Returns all backups, including failed ones, newest first. A backup whose record is missing or unreadable is left out.
- Authentication
- Bearer token How it works
- Permission
- Requires an administrator account.
Parameters
No parameters.
Returns
Returns an array of backup objects in data.
Errors
- 403 The caller is not an administrator.
- 500 The backups could not be listed.
curl "$VDF_BASE_URL/api/admin/backups" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/admin/backups`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/api/admin/backups",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"data": [
{
"id": "20260911T020003Z",
"created_at": "2026-09-11T02:00:03.418552+00:00",
"trigger": "scheduled",
"components": {
"postgres": {
"name": "postgres",
"size_bytes": 48213775,
"ok": true,
"skipped": false,
"error": null
},
"uploads": {
"name": "uploads",
"size_bytes": 231904512,
"ok": true,
"skipped": false,
"error": null
},
"vault": {
"name": "vault",
"size_bytes": 18350421,
"ok": true,
"skipped": false,
"error": null
}
},
"archive_size_bytes": 297431040,
"ok": true,
"error": null
},
{
"id": "20260910T163518Z",
"created_at": "2026-09-10T16:35:18.027114+00:00",
"trigger": "manual",
"components": {
"postgres": {
"name": "postgres",
"size_bytes": 48190211,
"ok": true,
"skipped": false,
"error": null
},
"uploads": {
"name": "uploads",
"size_bytes": 231688704,
"ok": true,
"skipped": false,
"error": null
},
"vault": {
"name": "vault",
"size_bytes": 18342117,
"ok": true,
"skipped": false,
"error": null
}
},
"archive_size_bytes": 297198592,
"ok": true,
"error": null
}
]
} Create a backup
POST /api/admin/backups
Creates a full backup of the platform database and stored files.
Exports the whole platform database, archives uploaded files and the Networks vault, and packs everything into one downloadable archive. No request body is needed.
The backup runs within the request, so the call returns only when it has finished. On a large installation this can take longer than your gateway allows for a response; if the request times out, use Retrieve backup status and List backups to find out what happened before you try again. After the backup, backups older than the retention period are deleted.
If a component fails, the backup is still kept and listed with ok set to false, and the call returns 500 with the backup in data.
- Authentication
- Bearer token How it works
- Permission
- Requires an administrator account.
Parameters
No parameters.
Returns
Returns the new backup object in data.
Errors
- 403 The caller is not an administrator.
- 409 A backup requested through the API is already in progress.
- 500 The backup failed. If it ran to completion,
dataholds the backup with the failing component'serror.
curl -X POST "$VDF_BASE_URL/api/admin/backups" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/admin/backups`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.post(
f"{os.environ['VDF_BASE_URL']}/api/admin/backups",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"data": {
"id": "20260911T083012Z",
"created_at": "2026-09-11T08:30:12.604318+00:00",
"trigger": "manual",
"components": {
"postgres": {
"name": "postgres",
"size_bytes": 48227350,
"ok": true,
"skipped": false,
"error": null
},
"uploads": {
"name": "uploads",
"size_bytes": 231904512,
"ok": true,
"skipped": false,
"error": null
},
"vault": {
"name": "vault",
"size_bytes": 18351006,
"ok": true,
"skipped": false,
"error": null
}
},
"archive_size_bytes": 297445376,
"ok": true,
"error": null
},
"error": null
} Retrieve a backup
GET /api/admin/backups/{backup_id}
Returns one backup.
- Authentication
- Bearer token How it works
- Permission
- Requires an administrator account.
Path parameters
-
backup_idstring RequiredID of the backup, such as
20260911T020003Z.
Returns
Returns the backup object in data.
Errors
- 403 The caller is not an administrator.
- 404 No backup has this ID.
curl "$VDF_BASE_URL/api/admin/backups/20260911T020003Z" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/admin/backups/20260911T020003Z`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/api/admin/backups/20260911T020003Z",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"data": {
"id": "20260911T020003Z",
"created_at": "2026-09-11T02:00:03.418552+00:00",
"trigger": "scheduled",
"components": {
"postgres": {
"name": "postgres",
"size_bytes": 48213775,
"ok": true,
"skipped": false,
"error": null
},
"uploads": {
"name": "uploads",
"size_bytes": 231904512,
"ok": true,
"skipped": false,
"error": null
},
"vault": {
"name": "vault",
"size_bytes": 18350421,
"ok": true,
"skipped": false,
"error": null
}
},
"archive_size_bytes": 297431040,
"ok": true,
"error": null
}
} Download a backup
GET /api/admin/backups/{backup_id}/download
Downloads a backup as a single archive file.
Returns the backup as one gzip-compressed tar archive (application/gzip), sent as an attachment. The archive holds the database export and the archives of uploaded files and of the Networks vault that the backup contains. It carries all of the platform's data, so store it as securely as the installation itself.
- Authentication
- Bearer token How it works
- Permission
- Requires an administrator account.
Path parameters
-
backup_idstring RequiredID of the backup, such as
20260911T020003Z.
Returns
Returns the backup archive as a file download.
Errors
- 403 The caller is not an administrator.
- 404 No downloadable archive exists for this ID.
curl "$VDF_BASE_URL/api/admin/backups/20260911T020003Z/download" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
-o download.bin const response = await fetch(`${process.env.VDF_BASE_URL}/api/admin/backups/20260911T020003Z/download`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const file = await response.blob(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/api/admin/backups/20260911T020003Z/download",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
stream=True,
timeout=30,
)
response.raise_for_status()
with open("download.bin", "wb") as output:
for chunk in response.iter_content(chunk_size=65536):
output.write(chunk) Restore a backup
POST /api/admin/backups/{backup_id}/restore
Restores components of a backup over the live installation.
Restores the chosen components from a backup, in place, while the installation is running. This is destructive and can't be undone:
postgresrestores the database from the backup's export. Every object in the export is dropped and re-created, so changes made to that data since the backup are lost.uploadsandvaultdelete everything currently stored for that component, then unpack the backup's copy. Files added since the backup are lost.
A component the backup does not contain is reported as skipped and left untouched.
Restoring the database through the API is off by default. Unless online restore has been enabled in the deployment configuration (see allow_online_restore in Retrieve backup status), any request that includes postgres, including one that omits components, is refused with 403, and the database has to be restored by your operator instead. To leave the database untouched, list only the file components you need, for example ["uploads"].
The restore runs within the request; plan it for a maintenance window. Each component reports its own result, and if any requested component fails the call returns 500 with the results in data.
- Authentication
- Bearer token How it works
- Permission
- Requires an administrator account.
Path parameters
-
backup_idstring RequiredID of the backup, such as
20260911T020003Z.
Body parameters application/json
-
confirmstring RequiredMust be exactly
RESTORE, to confirm that you mean to overwrite live data.Possible values-
RESTORE
-
-
componentsarray of stringsComponents to restore. Omitted, empty, or not an array means all three.
Possible values-
postgres -
uploads -
vault
-
Returns
Returns the restore result in data: the backup id, ok, and a components object with one result per requested component, in the same shape as a backup object's components.
Errors
- 400
confirmis notRESTORE,componentsnames an unknown component, or the ID contains characters a backup ID can't have. - 403 The caller is not an administrator, or the request includes
postgreswhile online database restore is disabled. - 404 No backup has this ID.
- 500 At least one requested component failed to restore;
data.componentsshows which and why.
curl -X POST "$VDF_BASE_URL/api/admin/backups/20260911T020003Z/restore" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"confirm": "RESTORE",
"components": [
"uploads"
]
}' const response = await fetch(`${process.env.VDF_BASE_URL}/api/admin/backups/20260911T020003Z/restore`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
confirm: 'RESTORE',
components: ['uploads'],
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.post(
f"{os.environ['VDF_BASE_URL']}/api/admin/backups/20260911T020003Z/restore",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"confirm": "RESTORE",
"components": ["uploads"],
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true,
"data": {
"id": "20260911T020003Z",
"ok": true,
"components": {
"uploads": {
"name": "uploads",
"size_bytes": 231904512,
"ok": true,
"skipped": false,
"error": null
}
}
}
} Delete a backup
DEL /api/admin/backups/{backup_id}
Permanently deletes a backup.
Deletes the backup and its downloadable archive. This can't be undone.
- Authentication
- Bearer token How it works
- Permission
- Requires an administrator account.
Path parameters
-
backup_idstring RequiredID of the backup, such as
20260911T020003Z.
Returns
Returns a success marker.
Errors
- 403 The caller is not an administrator.
- 404 No backup has this ID.
curl -X DELETE "$VDF_BASE_URL/api/admin/backups/20260910T163518Z" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/api/admin/backups/20260910T163518Z`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.delete(
f"{os.environ['VDF_BASE_URL']}/api/admin/backups/20260910T163518Z",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"success": true
}