## Восстановить базу из копии

`POST /v1/infra/servers/:id/db/restore`

Заменяет SQLite-файл приложения содержимым завершённой копии базы. Восстановление выполняется в фоновом режиме, а перед заменой платформа сохраняет защитную копию текущего файла.

## Параметры

| Параметр | Тип | Обяз. | Описание |
|----------|-----|:-----:|----------|
| `id` (path) | string (UUID) | да | ID приложения с `kind` равным `GALAXY_APP`, базу которого нужно заменить. Список: [`GET /v1/infra/servers`](/docs/infra/servers/list) |

## Поля запроса (body)

| Поле | Тип | Обяз. | Описание |
|------|-----|:-----:|----------|
| `backupId` | string | да | ID копии в статусе `COMPLETED` с неистёкшим `expiresAt`. Список: [`GET /db/backups`](/docs/infra/database/backups), поле `data.items[].id`. Копия может принадлежать другому приложению того же портала, в том числе удалённому, если у ключа есть доступ к данным этого приложения. Копии другого приложения: [`GET /db/backups?sourceAppId=...`](/docs/infra/database/backups) |
| `file` | string | нет | Путь к заменяемому файлу относительно тома `/data`, до 1024 байт в UTF-8. Без поля заменяется файл из переменной `VIBE_DB_PATH` контейнера приложения, а если она не задана — `app.db`. Абсолютный путь, сегменты `.` и `..`, пустые сегменты и управляющие символы отклоняются |

Других полей тело не принимает, размер тела — до 4 КиБ.

## Примеры

### curl — личный ключ

```bash
curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/APP_ID/db/restore" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"backupId":"BACKUP_ID"}'
```

### curl — OAuth-приложение

```bash
curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/APP_ID/db/restore" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"backupId":"BACKUP_ID"}'
```

### JavaScript — личный ключ

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${appId}/db/restore`,
  {
    method: 'POST',
    headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
    body: JSON.stringify({ backupId }),
  }
)
const { success, data, error } = await res.json()
if (!success) throw new Error(`${error.code}: ${error.message}`)
// Ход восстановления — в data.restore ответа GET /db/backups с тем же restoreId
console.log('Восстановление принято:', data.restoreId)
```

### JavaScript — OAuth-приложение

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${appId}/db/restore`,
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ backupId }),
  }
)
const { success, data, error } = await res.json()
if (!success) throw new Error(`${error.code}: ${error.message}`)
```

## Поля ответа

HTTP-статус успешного ответа — `202 Accepted`: восстановление принято в очередь, база ещё не заменена.

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | `true`, когда восстановление поставлено в очередь |
| `data.restoreId` | string | ID восстановления. По нему восстановление находится в поле `data.restore` ответа [`GET /db/backups`](/docs/infra/database/backups) |
| `data.backupId` | string | ID копии из запроса |
| `data.targetAppId` | string (UUID) | ID приложения, базу которого заменяют, — значение `id` из пути |
| `data.status` | string | Всегда `QUEUED` |

## Пример ответа

```json
{
  "success": true,
  "data": {
    "restoreId": "cm2r7x4k10003qv8n5d2b6w1z",
    "backupId": "9e4d2c1b-6a3f-4b8e-a7d5-0c1f2e3d4b5a",
    "targetAppId": "5c0e8f2a-3d1b-4a7e-9f60-2b8c4d1e7a93",
    "status": "QUEUED"
  }
}
```

## Пример ответа при ошибке

404 — копии с таким `backupId` нет:

```json
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Server not found"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `VALIDATION_ERROR` | Нет `backupId`, в теле неизвестное поле, недопустимые символы в `backupId` или `file` нарушает правила пути |
| 400 | `APP_DB_INVALID_FILE` | Поле `file` не передано, а значение `VIBE_DB_PATH` контейнера не указывает на допустимый путь внутри `/data` |
| 400 | `APP_DB_UNSUPPORTED_PLACEMENT` | Приложение размещено не в Галактике |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `INVALID_API_KEY` | Ключ не опознан |
| 403 | `INFRA_SCOPE_REQUIRED` | У ключа нет скоупа `vibe:infra` |
| 403 | `APP_DB_READONLY_KEY` | Ключ выпущен только для чтения |
| 403 | `APP_DB_DISABLED` | Работа с базой приложения не включена для портала |
| 404 | `NOT_FOUND` | Приложения с таким `id` нет на портале, оно удалено или у ключа нет к нему доступа |
| 404 | `NOT_FOUND` | Копии с таким `backupId` нет на портале, она ещё не в статусе `COMPLETED`, её срок хранения истёк или у ключа нет доступа к данным приложения, с которого она снята. Текст `message` одинаков для обоих случаев с `NOT_FOUND` |
| 404 | `APP_DB_NOT_FOUND` | У приложения нет тома с данными |
| 409 | `APP_DB_BUSY` | Восстановление не принято: у приложения идёт копирование, другое восстановление, запись в базу, деплой или переезд, для приложения или хоста запрещено пробуждение либо баланс портала заморожен. Повторите через `details.retryAfterSeconds` секунд |
| 413 | `PAYLOAD_TOO_LARGE` | Тело больше 4 КиБ |
| 422 | `APP_DB_BACKUP_INVALID` | Копия завершена, но в ней нет данных, нужных для восстановления |
| 429 | `RATE_LIMITED` | Превышен лимит запросов на запись для портала — [Лимиты](/docs/infra/database#лимиты). Пауза — в заголовке `Retry-After` |
| 503 | `APP_DB_TOOL_UNAVAILABLE` | Хост не подготовлен к работе с базой или платформа временно не может к нему обратиться. Готовность хоста — [`GET /app-db/prepare`](/docs/infra/database/prepare-status) |
| 503 | `user_self_deletion_pending` | Владелец ключа запросил удаление своего аккаунта на портале. Доступ вернётся после отмены удаления |

Полный список общих ошибок API — [Ошибки](/docs/errors).

## Известные особенности

**Ход восстановления.** Ответ `202` означает только приём запроса. Состояние читайте в `data.restore` ответа [`GET /db/backups`](/docs/infra/database/backups), сверяя `restoreId`. На тестовом приложении восстановление заняло 12 минут и прошло фазы по порядку: `VALIDATE`, `PREPARE`, `PRE_CHANGE`, `STAGE`, `STOPPING`, `SWAPPING`, `VERIFY`, `STARTING`, `CLEANUP`. После завершения данные базы совпали с копией. Восстановление остаётся в статусе `QUEUED`, пока на платформе выполняется другое восстановление или на том же хосте идёт копирование либо запись в базу.

**База занята до конца восстановления.** Пока восстановление не завершено, запись в базу этого приложения и новые копии отвечают `409 APP_DB_BUSY`. Чтение тоже получает `409 APP_DB_BUSY`: так ответило чтение сразу после запуска восстановления на живом вызове, а с фазы `STOPPING` чтение закрыто до конца восстановления.

**Перезапуск приложения.** Работающее приложение на фазе `STOPPING` останавливается и на фазе `STARTING` запускается снова. Приложение, которое было остановлено до восстановления, остаётся остановленным.

**Защитная копия перед заменой.** На фазе `PRE_CHANGE` платформа сохраняет текущий файл копией с `triggerType` равным `PRE_CHANGE` — она видна в [списке копий](/docs/infra/database/backups). Чтобы отменить восстановление, восстановите базу из этой копии. Если защитную копию создать не удалось, восстановление завершается со статусом `FAILED`, файл не заменяется. Если файла `file` у приложения ещё нет, защитная копия не создаётся.

**Сбой во время замены.** Сбой на фазах `VALIDATE`, `PREPARE` и `PRE_CHANGE` файл не трогает. Сбой на фазах от `STAGE` до `VERIFY` возвращает исходный файл через фазу `ROLLBACK`. В обоих случаях восстановление завершается со статусом `FAILED` и `errorCode` равным `APP_DB_RESTORE_FAILED`. Сбой на фазе `STARTING` и три неудачные попытки `ROLLBACK` переводят восстановление в фазу `RECOVERY_REQUIRED` со статусом `RUNNING` без автоматического отката: с фазы `STARTING` приложение уже работает с восстановленной базой. Такое восстановление ждёт службы поддержки, а база приложения до её вмешательства остаётся занятой.

Условия доступа к базе и правила хранения копий — [Когда база доступна](/docs/infra/database#когда-база-доступна) и [Копии и их хранение](/docs/infra/database#копии-и-их-хранение).

## Смотрите также

- [Получить список копий базы](/docs/infra/database/backups)
- [Создать копию базы](/docs/infra/database/snapshot)
- [Защитные копии перед записью](/docs/infra/database#защитные-копии-перед-записью)
- [База данных приложения](/docs/infra/database)
