List Database Backups

GET /v1/databases/{uuid}/backups

A backup belongs to the database, not to an app: a gzipped SQL dump of the whole database, taken on demand or by its backup schedule. This lists one page of the database's backups, newest first, with what the caller can do with them, the schedule, the connected apps and what a restore would do. A database created under Storage → Databases has backups like any other, whether or not an app uses it. See Database backups for the dashboard side (the database's Backups tab).

Requires Databases read and a plan with managed databases. Taking, restoring and scheduling backups are gated by the same plan entitlements as app backups: application_db_backup (back up), application_db_restore (restore), application_backup_schedule (turn a schedule on) and backup_retention_max (how many a schedule keeps). Every backup route is also on the agent plane under /v1/agent/databases/{uuid}/backups and /v1/agent/databases/{uuid}/backup-schedule, for account-scoped agent tokens. A database or backup of another account answers 404.

Query parameters

page int
1-based page number. Default 1.
page_size int
Backups per page, at most 100. Default 25; when you send page without page_size, the API's default page size (15).

Response (200 OK)

database object
{uuid, name, status, quota_paused, bundled_application_uuid}. bundled_application_uuid is the WordPress site that owns the database, or null.
locked bool
true when the plan grants neither a database backup nor a restore.
capabilities object
What the caller can do now (all bool): backup (the plan grants application_db_backup and the database is ready), restore (the plan grants application_db_restore, the database is ready and not paused), schedule (the plan grants application_db_backup and application_backup_schedule), download (the caller's role has Database data read).
retention_max int
The plan's backup_retention_max: the most backups a schedule keeps. 0 when the plan sets none.
in_progress bool
A backup of the database is pending or running.
restore_in_progress bool
A restore into the database is running.
backups array
The page of backup objects, newest first. Backups being deleted are left out.
total, page, page_size int
How many backups there are in all, and the page returned.
schedule object | null
The database's schedule, or null when it has none.
connected_apps array
The apps a restore affects: {application_uuid, application_name}, with legacy: true for an app bound to the database the older way, with no connection.
restore_warning string
What a restore does, naming the connected apps (the same text as the restore's warning).

Backup object

uuid string (uuid)
The backup's id: the {backup_uuid} of get, download, restore and delete.
database_uuid string (uuid)
The database it belongs to.
kind string
Always database.
trigger_source string
manual (on demand) or scheduled.
status string
pending → running → completed, or failed; deleting once a delete was requested.
restore_status string
none, restoring, restored or failed: the last restore of this backup.
size_bytes int
Size of the stored .sql.gz file; 0 until it has completed.
error / restore_error string
Why the backup / the last restore failed. Only present when it did.
created_at, started_at, completed_at, restored_at string
When it was requested, started, finished, and last restored. The last three are present once they happened.

Errors

403
Insufficient permissions for this action (no Databases read), No active account for this request, or Managed databases are not available on your plan.
404
database not found.
503
database_backups_unavailable: every database backup route answers this until the feature's database migration is applied (it is applied on ngris); databases_unavailable likewise for the Databases API.
Request
curl "https://api.ngris.com/v1/databases/019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18/backups?page=1&page_size=25" \ -H "X-API-KEY: <your_api_key>"
Response — 200 OK
{ "database": { "uuid": "019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18", "name": "orders-db", "status": "ready", "quota_paused": false, "bundled_application_uuid": null }, "locked": false, "capabilities": { "backup": true, "restore": true, "schedule": true, "download": true }, "retention_max": 7, "in_progress": false, "restore_in_progress": false, "backups": [ { "uuid": "019c3b52-8e4f-7c63-b2d5-6fa01c4e7b29", "database_uuid": "019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18", "kind": "database", "trigger_source": "scheduled", "status": "completed", "restore_status": "none", "size_bytes": 1048576, "created_at": "2026-10-19T03:00:00Z", "started_at": "2026-10-19T03:00:04Z", "completed_at": "2026-10-19T03:00:21Z" } ], "total": 1, "page": 1, "page_size": 25, "schedule": { "database_uuid": "019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18", "kind": "database", "enabled": true, "frequency": "daily", "hour_utc": 3, "retain_count": 7, "last_run_at": "2026-10-19T03:00:00Z", "next_run_at": "2026-10-20T03:00:00Z", "created_at": "2026-10-18T09:30:00Z", "updated_at": "2026-10-19T03:00:00Z" }, "connected_apps": [ { "application_uuid": "019be838-d261-7d9b-9499-71995a3a91c6", "application_name": "orders-api" } ], "restore_warning": "Restoring replaces ALL data in the database orders-db with this backup: changes made after it was taken are lost. It affects every application connected to it (orders-api): they keep running and see the restored data at once." }
Response — 503 (before the migration)
{ "error": "Database backups are not available yet: this feature is still being rolled out. Please try again later.", "code": "database_backups_unavailable" }

Back Up a Database

POST /v1/databases/{uuid}/backups

Take a backup now (the dashboard's Back up now). The backup is created pending; ngris then dumps the whole database (its tables, data and views) to a gzipped SQL file and it turns completed. Poll Get or the list for the status. No body is needed. One backup of a database runs at a time.

The database must be ready. A database paused over the plan's database limit can still be backed up: a backup only reads the data, and it is how you take the data out before deleting it. Requires Databases write and the plan's application_db_backup.

Response (201 Created)

{"backup": {…}}: the new backup object, status: "pending", trigger_source: "manual".

Errors

403
Database backup is not available on your plan., no Databases write, no active account, or no managed databases on the plan.
404
database not found.
409
backup_in_progress: A backup of this database is already in progress.
database_status: the database isn't ready (e.g. Not possible while the database is provisioning.); resource and status say which.
503
database_backups_unavailable or databases_unavailable.
Request
curl -X POST "https://api.ngris.com/v1/databases/019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18/backups" \ -H "X-API-KEY: <your_api_key>"
Response — 201 Created
{ "backup": { "uuid": "019c3b10-2a7c-7d41-9e8b-3c5d7f1a2b64", "database_uuid": "019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18", "kind": "database", "trigger_source": "manual", "status": "pending", "restore_status": "none", "size_bytes": 0, "created_at": "2026-10-19T10:15:00Z" } }
Response — 409 (one is running)
{ "error": "A backup of this database is already in progress.", "code": "backup_in_progress" }

Get a Database Backup

GET /v1/databases/{uuid}/backups/{backup_uuid}

One backup of the database, in any status. Requires Databases read.

Response (200 OK)

{"backup": {…}} (backup object).

Errors

403
No Databases read, no active account, or no managed databases on the plan.
404
database not found or backup not found.
503
database_backups_unavailable or databases_unavailable.
Request
curl "https://api.ngris.com/v1/databases/019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18/backups/019c3b10-2a7c-7d41-9e8b-3c5d7f1a2b64" \ -H "X-API-KEY: <your_api_key>"
Response — 200 OK
{ "backup": { "uuid": "019c3b10-2a7c-7d41-9e8b-3c5d7f1a2b64", "database_uuid": "019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18", "kind": "database", "trigger_source": "manual", "status": "completed", "restore_status": "none", "size_bytes": 1052160, "created_at": "2026-10-19T10:15:00Z", "started_at": "2026-10-19T10:15:03Z", "completed_at": "2026-10-19T10:15:19Z" } }

Download a Database Backup

GET /v1/databases/{uuid}/backups/{backup_uuid}/download

Stream a completed backup: the gzipped SQL dump, Content-Type: application/gzip, as an attachment named <database name>-<backup uuid>.sql.gz (characters other than letters, digits, ., _ and - in the name become -). The dump has no DROP TABLE statements: import it into an empty database.

The dump is the database's data, so this needs the role's Database data read permission (not Databases read). The account owner and the built-in Admin role have it; a custom role has it when its Database data row allows read (custom roles that existed before databases got their own permissions have it off). The list's capabilities.download says whether the caller has it. Every download is recorded in the account audit log.

Errors

403
Insufficient permissions for this action (no Database data read), no active account, or no managed databases on the plan.
404
database not found, backup not found, or backup artifact not found (the stored file is gone).
409
Only a completed backup can be downloaded.
502
failed to read backup artifact: the storage couldn't be read; retry.
503
Backup storage is not configured., database_backups_unavailable or databases_unavailable.
Request
curl -L -o orders-db.sql.gz \ "https://api.ngris.com/v1/databases/019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18/backups/019c3b10-2a7c-7d41-9e8b-3c5d7f1a2b64/download" \ -H "X-API-KEY: <your_api_key>"
Response — 200 OK (headers)
Content-Type: application/gzip Content-Disposition: attachment; filename="orders-db-019c3b10-2a7c-7d41-9e8b-3c5d7f1a2b64.sql.gz" Content-Length: 1052160

Restore a Database Backup

POST /v1/databases/{uuid}/backups/{backup_uuid}/restore
⚠ Destructive, for every connected app. A restore replaces all the data in the database with the backup: anything written after the backup was taken is lost, and there is no undo. Every app connected to the database keeps running and sees the restored data as soon as the restore finishes. Take a fresh backup first if you might want to come back.

Restore a completed backup into its database. The call is accepted asynchronously (202): the backup's restore_status goes restoring → restored, or failed with restore_error. ngris first drops every table and view in the database, then imports the dump, so until the import finishes connected apps can find tables missing. A restored view gets ngris's own internal user for this database as its definer (with the same rights as a read-write user on it), so it works as before. No body is needed; the dashboard asks you to type the database's name first.

One restore into a database runs at a time. Refused while the database is paused over the plan's database limit (it is read-only then) or isn't ready. Requires Databases update and the plan's application_db_restore.

Response (202 Accepted)

status string
restoring.
backup object
The backup, restore_status: "restoring".
warning string
What the restore does, naming every connected app, e.g. … It affects every application connected to it (orders-api): they keep running and see the restored data at once. With no app: … No application is connected to it.
connected_apps array
The apps it affects, {application_uuid, application_name, legacy?}.

Errors

403
Database restore is not available on your plan., no Databases update, no active account, or no managed databases on the plan.
404
database not found or backup not found.
409
quota_paused: the database is paused over your plan's database limit; it can't be restored until the account has room.
database_status: the database isn't ready.
restore_in_progress: A restore into this database is already in progress.
backup_not_restorable: Only a completed backup can be restored.
503
database_backups_unavailable or databases_unavailable.
Request
curl -X POST \ "https://api.ngris.com/v1/databases/019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18/backups/019c3b10-2a7c-7d41-9e8b-3c5d7f1a2b64/restore" \ -H "X-API-KEY: <your_api_key>"
Response — 202 Accepted
{ "status": "restoring", "backup": { "uuid": "019c3b10-2a7c-7d41-9e8b-3c5d7f1a2b64", "database_uuid": "019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18", "kind": "database", "trigger_source": "manual", "status": "completed", "restore_status": "restoring", "size_bytes": 1052160, "created_at": "2026-10-19T10:15:00Z", "started_at": "2026-10-19T10:15:03Z", "completed_at": "2026-10-19T10:15:19Z" }, "warning": "Restoring replaces ALL data in the database orders-db with this backup: changes made after it was taken are lost. It affects every application connected to it (orders-api): they keep running and see the restored data at once.", "connected_apps": [ { "application_uuid": "019be838-d261-7d9b-9499-71995a3a91c6", "application_name": "orders-api" } ] }
Response — 409 (paused)
{ "error": "<why the database is paused and how to make room>", "code": "quota_paused", "quota_paused": true, "quota_paused_resource": "database", "quota_paused_key": "managed_database", "quota_paused_limit": 3 }

Delete a Database Backup

DELETE /v1/databases/{uuid}/backups/{backup_uuid}

Delete a completed or failed backup. It turns deleting and leaves the list; ngris then removes the stored file, then the record. This can't be undone. Allowed while the database is paused. Requires Databases delete.

You don't need to delete backups before deleting the database: deleting a database deletes all its backups.

Response (202 Accepted)

{"backup": {…}} with status: "deleting".

Errors

403
No Databases delete, no active account, or no managed databases on the plan.
404
database not found or backup not found.
409
backup_not_deletable: A backup can be deleted once it has completed or failed. (it is still pending or running, or already deleting).
503
database_backups_unavailable or databases_unavailable.
Request
curl -X DELETE \ "https://api.ngris.com/v1/databases/019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18/backups/019c3b10-2a7c-7d41-9e8b-3c5d7f1a2b64" \ -H "X-API-KEY: <your_api_key>"
Response — 202 Accepted
{ "backup": { "uuid": "019c3b10-2a7c-7d41-9e8b-3c5d7f1a2b64", "database_uuid": "019c2a41-7d3e-7b52-a1c4-5e9f0b3d6a18", "kind": "database", "trigger_source": "manual", "status": "deleting", "restore_status": "none", "size_bytes": 1052160, "created_at": "2026-10-19T10:15:00Z", "started_at": "2026-10-19T10:15:03Z", "completed_at": "2026-10-19T10:15:19Z" } }

Audit trail

Every backup request, download, restore request, delete request and schedule change is recorded in the account audit log with event_type database: Database backup requested: <name>, Database backup downloaded: <name>, Database restore requested: <name>, Database backup deletion requested: <name> and Database backup schedule set: <name> (…).