## POST /api/v2/vps/{id}/backups/{backupId}/actions/restore-to-payg

**Restore backup to a new Cloud VM**

Create a new pay-as-you-go Cloud VM from one existing VPS backup. The original VPS is used only to confirm ownership and locate the backup; the restore writes to a newly provisioned Cloud VM. Get `{id}` from `GET /api/v2/vps` `data[].id`, get `{backupId}` from `GET /api/v2/vps/{id}/backups` `backups[].id`, and check the backup restore action gate before calling. If the account cannot use Cloud VM yet, the response explains the blocker. Optional request fields let the caller choose the new VM name, region, CPU, memory, and storage. If omitted, the API chooses safe defaults from the source VPS and backup size.

### Related Endpoints

- `POST /api/v2/vps/{id}/backups/{backupId}/actions/restore`: Restore VPS backup
- `DELETE /api/v2/vps/{id}/backups/{backupId}`: Delete VPS backup
- `GET /api/v2/vps/{id}/backups`: List VPS backups

### Headers

- `Accept`: application/json
- `Authorization`: Bearer YOUR_API_KEY
- Required API scopes: `backup:vm`, `write:billing`
- `Content-Type`: application/json

### Parameters

- `id` (path, string, required): Public VPS ID from `GET /api/v2/vps` `data[].id`. Do not invent this value; use the exact ID returned by the referenced API response. Example: `vps_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `backupId` (path, string, required): Public backup ID from `GET /api/v2/vps/{id}/backups` `backups[].id`. Do not invent this value; use the exact ID returned by the referenced API response. Example: `bkp_01hxa3b4c5d6e7f8g9h0j1k2m3`

### Request Body

- `name` (string, optional): Hostname label for the new Cloud VM. Omit it to let the API generate one. Example: `restore-web-01`
- `region` (string, optional): Deployment region for the new Cloud VM. Omit it to use the default region. Example: `stockholm`
- `cpuCores` (integer, optional) [min: 1, max: 32]: CPU cores for the new Cloud VM. Omit it to mirror the source VPS within supported limits. Example: `2`
- `memoryGb` (integer, optional) [min: 1, max: 256]: Memory in GB for the new Cloud VM. Omit it to mirror the source VPS within supported limits. Example: `4`
- `storageGb` (integer, optional) [min: 1, max: 2000]: Storage in GB for the new Cloud VM. Must be at least the larger of the source VPS storage and backup size. Omit it to let the API choose the required size. Example: `80`

### Request Examples

#### Restore with API-selected defaults

```bash
curl -X POST "https://cloud.hostup.se/api/v2/vps/vps_01hxa3b4c5d6e7f8g9h0j1k2m3/backups/bkp_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/restore-to-payg" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
```

#### Restore with selected Cloud VM resources

```bash
curl -X POST "https://cloud.hostup.se/api/v2/vps/vps_01hxa3b4c5d6e7f8g9h0j1k2m3/backups/bkp_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/restore-to-payg" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "restore-web-01",
    "region": "stockholm",
    "cpuCores": 2,
    "memoryGb": 4,
    "storageGb": 80
  }'
```

```json
{
  "name": "restore-web-01",
  "region": "stockholm",
  "cpuCores": 2,
  "memoryGb": 4,
  "storageGb": 80
}
```

### Response Schema

- `operation` (object, optional)
- `operation.status` (string, required) Example: `queued`
  Allowed values: pending, queued, in_progress, completed, failed
- `operation.jobId` (string, required) Example: `job_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `operation.pollUrl` (string, required) Example: `/api/jobs/job_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `operation.result` (object,null, optional) Example: `null`

### Responses

#### 202 - Restore to a new Cloud VM was queued.
```json
{
  "operation": {
    "status": "queued",
    "jobId": "job_01hxa3b4c5d6e7f8g9h0j1k2m3",
    "pollUrl": "/api/jobs/job_01hxa3b4c5d6e7f8g9h0j1k2m3"
  }
}
```

#### 400 - Invalid request. The response body is an RFC 7807 Problem Details document.
```json
{
  "type": "https://developer.hostup.se/errors/invalid_request",
  "title": "Invalid request",
  "status": 400,
  "detail": "The request body failed validation.",
  "code": "invalid_request",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z",
  "errors": [
    {
      "pointer": "/items/0/domainName",
      "detail": "`domainName` is required.",
      "code": "invalid_request"
    }
  ]
}
```

#### 401 - Unauthorized. Authentication is required.
```json
{
  "type": "https://developer.hostup.se/errors/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Authentication is required.",
  "code": "unauthorized",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 403 - Forbidden. The caller lacks a required scope or does not own the resource.
```json
{
  "type": "https://developer.hostup.se/errors/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "The caller lacks a required scope or does not own the resource.",
  "code": "forbidden",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 404 - Not found. The resource does not exist or is not owned by the caller.
```json
{
  "type": "https://developer.hostup.se/errors/not_found",
  "title": "Not found",
  "status": 404,
  "detail": "The requested resource could not be found.",
  "code": "not_found",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 429 - Rate limited. Retry after the limit resets. 429 responses include `Retry-After` seconds plus `X-RateLimit-*` headers.
```json
{
  "type": "https://developer.hostup.se/errors/rate_limit_exceeded",
  "title": "Too many requests",
  "status": 429,
  "detail": "Too many requests. Retry after the limit resets.",
  "code": "rate_limit_exceeded",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 500 - Internal error. Retry later or contact support if the issue persists.
```json
{
  "type": "https://developer.hostup.se/errors/internal_error",
  "title": "Internal server error",
  "status": 500,
  "detail": "An unexpected error occurred. Retry later or contact support if the issue persists.",
  "code": "internal_error",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```
