> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dbhost.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Restore a managed-roles database from its backup

> Restore a DBHost database with managed SQL roles in place from one of its own verified backups, then advance the operation until it succeeds.

Restores a database with managed SQL roles in place from a verified DBHost
backup of that same database. The restore replaces the current contents, so
writes made after the backup are no longer present. The role usernames and
passwords stay the same. For other database types, see
[Restore from a DBHost backup](/guides/restore-from-backup).

Every database with managed roles can be restored, whether it has only its
owner, runtime and read-only roles or also additional roles. The backup must
list the same roles the database has now: after you add or remove an
additional role, restore from a backup taken after that change. An older
backup is refused when its roles no longer match: the restore operation then
ends as `failed` with a message saying so, and the database is left unchanged.
Start a new restore from a backup taken after the latest role change.

Both endpoints require Pro or Business and a **full-account** API key. A key
scoped to selected databases receives `403 KEY_SCOPE_DENIED`; see
[Authentication](/api-reference/authentication). Every response, including
errors, is sent with `Cache-Control: no-store`.

## How it works

1. Find a backup ID with `GET /api/v1/databases/{id}/backups`.
2. Reserve the restore with `POST /api/v1/databases/{id}/managed-restores`.
   This returns an operation ID and does not change the database yet.
3. Call `POST /api/v1/operations/{operationId}/managed-restore/advance`
   repeatedly until it returns `200` with `status: "succeeded"`.
4. Read progress at any time with
   [`GET /api/v1/operations/{operationId}`](/api-reference/operations/get).

Expect open connections to drop during the cutover; your application must
reconnect. While the restore is in progress, role rotations and revocations,
creating or removing additional roles, and extension changes are refused.

## Reserve a restore

```http theme={null}
POST /api/v1/databases/{id}/managed-restores
Authorization: Bearer <api-key>
Idempotency-Key: restore-2026-10-14-orders
Content-Type: application/json

{"backupId":"6f1c2d3e-4b5a-4c6d-8e7f-9a0b1c2d3e4f"}
```

### Path parameters

| Parameter | Type | Description |
| - | - | - |
| `id` | uuid | Database ID |

### Headers

| Header | Required | Description |
| - | - | - |
| `Idempotency-Key` | Yes | 1–128 characters from `A-Z`, `a-z`, `0-9`, `.`, `_`, `:` and `-` |

Generate the key once and keep it. If a request times out or the result is
uncertain, send the same request with the same key to get the original
operation back. Do not send a new key to retry; that would reserve a second
restore. A key belongs to one restore across your account: using it with a
different database or backup returns `409 MANAGED_ROLE_CONFLICT`.

### Body

The body must contain exactly one field:

| Field | Type | Description |
| - | - | - |
| `backupId` | uuid | ID of a backup of this database, in lowercase UUID form |

The backup must be a verified DBHost backup of this same database that
includes its managed role manifest and is still within retention. You cannot
restore one database's backup into another database.

### Response

```json 202 Accepted theme={null}
{
  "operationId": "3f0c8a62-1d2b-4c5e-9f7a-0b1c2d3e4f5a",
  "status": "queued",
  "stage": "queued"
}
```

The status code is `202` until the operation has succeeded, then `200`. If
the key refers to a restore that failed or was canceled, the response is
`409 RESTORE_OPERATION_TERMINAL`; start a new restore with a new key.

The reservation is refused with `409 MANAGED_ROLE_CONFLICT` when the backup
does not qualify, a role rotation or revocation on the database is
unfinished, an additional role is still being created or removed, or another
operation holds the database.

## Advance the restore

```http theme={null}
POST /api/v1/operations/{operationId}/managed-restore/advance
Authorization: Bearer <api-key>
```

Send no body. Each call moves the operation forward from its current state
and returns it:

```json 202 Accepted theme={null}
{
  "operationId": "3f0c8a62-1d2b-4c5e-9f7a-0b1c2d3e4f5a",
  "status": "running",
  "stage": "managed_restore_source_verified"
}
```

Repeat the call for the same operation until it returns `200` with
`"status": "succeeded"`. Calling it again after success returns the same
result. `stage` is informational and its values can change; rely on `status`.
Do not reserve a second restore to retry a stage.

DBHost verifies the backup and restores into an isolated copy before it
switches over. If verification fails, the current database is left
unchanged.

## Errors

| Status | Code | Endpoint | Description |
| - | - | - | - |
| 400 | `VALIDATION_ERROR` | Reserve | Invalid database ID, body is not exactly `{"backupId": "<uuid>"}`, or missing or invalid `Idempotency-Key` |
| 400 | `INVALID_JSON` | Reserve | Request body is not valid JSON |
| 401 | `UNAUTHORIZED` | Both | Missing or invalid API key |
| 403 | `PLAN_API_ACCESS_REQUIRED` | Both | API access requires Pro or Business |
| 403 | `KEY_SCOPE_DENIED` | Both | The key is scoped to selected databases; use a full-account key |
| 404 | `OPERATION_NOT_FOUND` | Advance | No managed restore operation with this ID is visible to the account |
| 409 | `RESTORE_SOURCE_REJECTED` | Advance | DBHost refused the selected backup (it no longer matches the database's roles, is missing, or failed verification). `error.message` says why; the database is unchanged and the operation is over. Choose another backup and start a new restore with a new key |
| 409 | `RESTORE_OPERATION_TERMINAL` | Both | The restore failed or was canceled; start a new one with a new key. After a refused backup, `error.message` carries the same reason |
| 409 | `MANAGED_ROLE_CONFLICT` | Both | The backup or database does not qualify, the key is bound to a different restore, or the operation cannot advance from its current state |
| 413 | `PAYLOAD_TOO_LARGE` | Reserve | Request body is larger than the API limit |
| 429 | `RATE_LIMITED` | Both | Too many requests; retry after the `Retry-After` header |
| 503 | `FEATURE_DISABLED` | Both | Managed restore is temporarily unavailable; retry later |
| 503 | `MAINTENANCE` | Both | DBHost is in a maintenance window; retry later |
| 500 | `INTERNAL_ERROR` | Both | The request failed; retry with the same key or advance the same operation |

The reserve endpoint allows six requests per hour per API key, including
retries.

The dashboard and the CLI have no restore action for databases with managed
SQL roles.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.