Backups
List an environment's backups, look one up, obtain presigned download URLs for the database dump, filestore archive, and manifest, and restore a backup into its environment, all over your API key.
Base URL: https://api.oec.sh/api/public/v1
Backup Status Values
| Status | Meaning |
|---|---|
pending | Queued, has not started yet. |
running | Backup is being created. |
completed | Backup finished and download URLs can be issued. |
failed | Backup failed (see error_message on the backup object). |
cancelled | Backup was cancelled. |
Only completed backups can be downloaded or restored.
Backup Type Values
| Type | Meaning |
|---|---|
manual | Triggered on demand from the dashboard or an admin action. |
scheduled | Created by the environment's backup policy. |
pre_deploy | Snapshot taken automatically before a deployment. |
List Backups for an Environment
GET /environments/{env_id}/backupsReturns the environment's backups in reverse-chronological order.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
env_id | UUID | The environment ID. |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status (pending, running, completed, failed, cancelled). |
backup_type | string | Filter by type (manual, scheduled, pre_deploy). |
page | integer | Page number, starts at 1. Default: 1. |
page_size | integer | Results per page. Min 1, max 100. Default: 20. |
Response — 200 OK
{
"items": [
{
"id": "9c2ad33c-7e5d-4d23-8f8c-9c3c5dc6c1f1",
"environment_id": "5a296461-9222-40da-91f5-9e912890dc1b",
"status": "completed",
"backup_type": "scheduled",
"database_size": 432198144,
"filestore_size": 211345920,
"total_size": 643544064,
"compressed_size": 218657280,
"started_at": "2026-05-22T18:00:00Z",
"completed_at": "2026-05-22T18:04:32Z",
"duration_seconds": 272,
"expires_at": "2026-06-21T18:04:32Z",
"is_verified": true,
"verified_at": "2026-05-22T18:05:01Z",
"notes": null,
"created_at": "2026-05-22T18:00:00Z"
}
],
"total": 31,
"page": 1,
"page_size": 20,
"total_pages": 2
}Example
# All completed backups for an environment
curl "https://api.oec.sh/api/public/v1/environments/YOUR_ENV_ID/backups?status=completed" \
-H "Authorization: Bearer YOUR_API_KEY"Get Download URLs
GET /backups/{backup_id}/downloadReturns presigned URLs for the database dump, filestore archive, and manifest. The backup must be in completed status.
URLs are time-limited. Choose a TTL between 5 minutes and 24 hours via the expires_in parameter. Treat the URLs as one-time tokens — anyone with the URL can download the file until it expires.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
backup_id | UUID | The backup ID. |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
expires_in | integer | URL validity in seconds. Min 300 (5 minutes), max 86400 (24 hours). Default: 3600 (1 hour). |
Response — 200 OK
{
"backup_id": "9c2ad33c-7e5d-4d23-8f8c-9c3c5dc6c1f1",
"database_url": "https://storage.example.com/.../dump.sql?X-Amz-Signature=...",
"filestore_url": "https://storage.example.com/.../filestore.tar.gz?X-Amz-Signature=...",
"manifest_url": "https://storage.example.com/.../manifest.json?X-Amz-Signature=...",
"expires_in": 3600,
"expires_at": "2026-05-23T03:45:55Z",
"use_streaming": false
}When use_streaming is true, the storage provider cannot issue presigned URLs directly (e.g. some GCP configurations); the URLs returned will stream through the platform instead.
Errors
| Status | Reason |
|---|---|
400 | Backup is not in completed status, so no downloadable files exist yet. |
404 | Backup not found, or the API key's scope does not cover this backup's organization or project. |
Example
# Get URLs valid for 24 hours
curl "https://api.oec.sh/api/public/v1/backups/YOUR_BACKUP_ID/download?expires_in=86400" \
-H "Authorization: Bearer YOUR_API_KEY"
# Then download with the returned URL (no auth header needed — the URL is presigned)
curl -o dump.sql "<database_url from response>"Get a Backup
GET /backups/{backup_id}Returns one backup, in the same shape as an item of the backup list. Works with a read-only key.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
backup_id | UUID | The backup ID. |
Response: 200 OK
The same object as one entry of items in List Backups for an Environment.
Errors
| Status | Reason |
|---|---|
404 | Backup not found, or the API key's scope does not cover this backup's organization or project. |
Example
curl "https://api.oec.sh/api/public/v1/backups/YOUR_BACKUP_ID" \
-H "Authorization: Bearer YOUR_API_KEY"Restore a Backup
POST /backups/{backup_id}/restoreRestores a completed backup into the environment it was taken from. Requires a full-access key.
A restore overwrites the environment's current database and files with the contents of the backup. Anything written since the backup was taken is replaced. To confirm, send the header X-Confirm-Restore: true; without it the request is refused with 400.
What happens:
- A safety backup of the environment's current data is taken first whenever the environment has data to back up, so the restore can be undone by restoring that backup. If the safety backup fails, the restore is aborted and the environment's data is left unchanged. (The failure message may mention skipping the safety backup; only the dashboard offers that.)
- The database and the filestore are both restored. The environment restarts during the restore.
- The restore runs in the background. Poll
poll_url(the same task endpoint as actions) until it reaches a final status.
Only the backup's own environment can be the target. To restore into another environment, a new environment or another server, use the dashboard.
The environment must be running, stopped, paused or error (restoring a backup is a way to recover an environment in error).
Path Parameters
| Parameter | Type | Description |
|---|---|---|
backup_id | UUID | The backup to restore. |
Headers
| Header | Required | Description |
|---|---|---|
X-Confirm-Restore | Yes | Must be exactly true. |
Idempotency-Key | No | Unique string to deduplicate retries. A retry with the same key within 24 hours returns the first response instead of starting a second restore. A retry sent while the first request is still being processed gets 409 concurrent_action; retry after a few seconds to receive the first response. |
Response: 202 Accepted
{
"task_id": "a1b2c3d4-...",
"status": "queued",
"environment_id": "5a296461-9222-40da-91f5-9e912890dc1b",
"backup_id": "9c2ad33c-7e5d-4d23-8f8c-9c3c5dc6c1f1",
"poll_url": "/api/public/v1/deployments/a1b2c3d4-..."
}Errors
| Status | Error code | Reason |
|---|---|---|
400 | confirm_required | The X-Confirm-Restore: true header is missing. |
400 | backup_not_completed | The backup is not in completed status. |
400 | backup_files_missing | The backup's files are no longer in storage. |
400 | restore_refused | The restore was refused; the message says why. |
402 | The organization's subscription is blocked. | |
403 | read_only_key | The API key is read-only. |
404 | not_found | Backup not found, or the API key's scope does not cover this backup's organization or project. |
409 | environment_deleted | The environment the backup was taken from has been deleted. |
409 | environment_not_restorable | The environment is being deployed or cloned, was never deployed, or has no server. |
409 | concurrent_action | Another action was queued for this environment in the last few seconds, or a retry arrived while the first request with the same Idempotency-Key was still being processed. Retry shortly. |
409 | task_in_progress | Another task is queued or running for this environment; task_id names it. |
409 | restore_in_progress | A restore of this environment is already running. |
503 | enqueue_failed | The restore could not be queued. Retry after the Retry-After delay. |
Example
# Generate the key once and reuse it for every retry of this restore.
KEY=$(uuidgen)
curl -X POST "https://api.oec.sh/api/public/v1/backups/YOUR_BACKUP_ID/restore" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Confirm-Restore: true" \
-H "Idempotency-Key: $KEY"Common Pattern: Latest Backup for an Environment
# 1. Find the most recent completed backup
BACKUP_ID=$(curl -s "https://api.oec.sh/api/public/v1/environments/YOUR_ENV_ID/backups?status=completed&page_size=1" \
-H "Authorization: Bearer YOUR_API_KEY" \
| jq -r '.items[0].id')
# 2. Get download URLs
curl "https://api.oec.sh/api/public/v1/backups/$BACKUP_ID/download?expires_in=3600" \
-H "Authorization: Bearer YOUR_API_KEY"