API: backups, restores and clones

Run backups, change schedules, build .zip downloads, restore and clone.

Updated Oct 11, 2026

List and run backups

GET /sites/{id}/backups

POST /sites/{id}/backups

GET /backups/{id}

Reading needs read (filter with ?status=failed); running needs backups. Running answers 202. Poll GET /backups/{id} until status is succeeded or failed.

curl -X POST https://app.wpforeman.com/api/v1/sites/12/backups \
  -H "Authorization: Bearer YOUR_TOKEN"
{ "data": { "id": 481, "site_id": 12, "trigger": "manual", "status": "queued", "stage": null, ... } }

Storage

GET /storage

Ability: read. Your connected storage: id, provider (gdrive, dropbox, s3), name, status, last_error.

PUT /sites/{id}/backup-storage

Ability: backups. Body: {"connection_id": 3} to keep the site’s backups in that storage, or {"connection_id": null} for WP Foreman storage. Returns 202; the move runs in the background (see Storage options). Restores accept from_copy (a connection id) to restore from the site’s extra copy.

Backup fields: status (queued, running, succeeded, failed, expired = removed by the keep rules), stage (files, database, upload), files_total, bytes_total, files_changed, bytes_changed, tables_total, tables_changed, added_bytes (storage this backup added, after dedup and compression), copy_status (queued, running, succeeded, failed, or null when there is no extra copy) and copied_at, skipped_files, error, timestamps.

Backup settings

GET /sites/{id}/backup-settings

PATCH /sites/{id}/backup-settings

Ability: backups to change. Send only what you’re changing:

{
  "enabled": true,
  "frequency": "6h",            // monthly | weekly | daily | 12h | 6h | 1h
  "start_time": "00:17",        // your account timezone
  "day_of_week": 1,             // weekly, 0 = Sunday
  "day_of_month": 15,           // monthly, 1–28
  "exclude_paths": ["wp-content/uploads/videos"],
  "exclude_tables": ["wp_wfhits"],
  "foreign_tables": "exclude",  // include | exclude
  "notify": "failures",         // failures | all | none
  "copy_connection_id": 3       // extra copy to a connected Google Drive / Dropbox, or null
}

Download as .zip

POST /backups/{id}/zip

Ability: backups. Starts building the .zip (202) or returns the ready one (200) with download_url and expires_at. Call again to poll. The download link itself needs a signed-in browser.

Restore

POST /backups/{id}/restore

Ability: restore. Body:

{ "scope": "full" }                                  // whole site
{ "scope": "files" }                                 // files only
{ "scope": "database" }                              // database only
{ "scope": "paths", "paths": ["wp-content/uploads/2026/10/logo.png"] }
// optional: "include_wp_config": true

Answers 202 with a restore record. Poll GET /restores/{id}; stage moves through safety, download, files, database, finish (clones also pass through replace while URLs are updated). safety_backup_id is the backup taken just before, for undoing.

Clone to another site

POST /backups/{id}/clone

Ability: restore. Body: { "target_site_id": 15 }. The destination must be connected with plugin 0.5.0+. URLs and table prefixes are fixed automatically; rows_replaced reports how many database rows had URLs updated.

Restore history

GET /sites/{id}/restores

GET /restores/{id}

Was this helpful?