## POST /api/v2/placement-groups/{id}/actions/resolve

**Restart one VPS to separate a placement group**

Start the self-serve fix for a placement group that needs attention after automatic separation could not finish. The operation briefly shuts down one colocated VPS, moves it to separate hardware, and starts it again. Call this only when the placement group detail has `needsAttention: true` and `actions.canResolve.allowed: true`. The 202 response body is the refreshed placement group detail (there is no separate operation object); poll `GET /api/v2/placement-groups/{id}/status` until `health` returns to `ok`.

### Related Endpoints

- `GET /api/v2/placement-groups/{id}`: Get VPS placement group detail
- `PATCH /api/v2/placement-groups/{id}`: Rename a VPS placement group
- `DELETE /api/v2/placement-groups/{id}`: Delete a VPS placement group

### Headers

- `Accept`: application/json
- `Authorization`: Bearer YOUR_API_KEY
- Required API scope: `write:vm`
- `Content-Type`: application/json

### Parameters

- `id` (path, string, required): Placement group public ID. Do not invent this value; use the exact ID returned by the referenced API response. Example: `pg_01hxa3b4c5d6e7f8g9h0j1k2m3`

### Request Body

- `acceptRestart` (boolean, required): Must be `true` to confirm the short restart of one VPS.

### Request Example

```bash
curl -X POST "https://cloud.hostup.se/api/v2/placement-groups/pg_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/resolve" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "acceptRestart": true
  }'
```

```json
{
  "acceptRestart": true
}
```

### Response Schema

- `id` (string, required) Example: `pg_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `name` (string, required) Example: `Production database`
- `policy` (string, required) Example: `spread`
  Allowed values: spread
- `health` (string, required) Example: `reconciling`
  Allowed values: ok, reconciling, violation
- `needsAttention` (boolean, required) Example: `false`
- `compatibilityKey` (string, required, nullable): Nullable (may be null when not applicable). Example: `pgcmp_9f6a3b2c1d0e8a7b`
- `members` (array<object>, required)
- `members[].vpsId` (string, required) Example: `vps_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `members[].name` (string, required) Example: `db-replica`
- `members[].instanceUrl` (string, required) Example: `/instance/vps_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `members[].placementSet` (string, required) Example: `b`
  Allowed values: a, b, c
- `members[].status` (string, required) Example: `migrating`
  Allowed values: placed, migrating, colocated, unknown
- `members[].addedAt` (string, required) Example: `2026-06-28T10:02:00.000Z`
- `actions` (object, required)
- `actions.canRename` (object, required)
- `actions.canRename.allowed` (boolean, required) Example: `true`
- `actions.canRename.reason` (string, required, nullable): Nullable (may be null when not applicable). Example: `null`
- `actions.canDelete` (object, required)
- `actions.canDelete.allowed` (boolean, required) Example: `true`
- `actions.canDelete.reason` (string, required, nullable): Nullable (may be null when not applicable). Example: `null`
- `actions.canAddMember` (object, required)
- `actions.canAddMember.allowed` (boolean, required) Example: `true`
- `actions.canAddMember.reason` (string, required, nullable): Nullable (may be null when not applicable). Example: `null`
- `actions.canResolve` (object, required)
- `actions.canResolve.allowed` (boolean, required) Example: `false`
- `actions.canResolve.reason` (string, required, nullable): Why the resolve action is unavailable: `not_needed` when the group has no issue a restart can fix, `no_restart_target` when no suitable separate hardware is available right now. `null` when `allowed` is `true`. Example: `not_needed`
  Allowed values: not_needed, no_restart_target
- `createdAt` (string, required) Example: `2026-06-28T10:00:00.000Z`
- `updatedAt` (string, required) Example: `2026-06-28T10:05:00.000Z`

### Responses

#### 202 - Separation was accepted and queued. The returned placement group detail is normally `reconciling` while the move runs; poll `GET /api/v2/placement-groups/{id}/status` until `health` is `ok`.
```json
{
  "id": "pg_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "name": "Production database",
  "policy": "spread",
  "health": "reconciling",
  "needsAttention": false,
  "compatibilityKey": "pgcmp_9f6a3b2c1d0e8a7b",
  "members": [
    {
      "vpsId": "vps_01hxa3b4c5d6e7f8g9h0j1k2m3",
      "name": "db-replica",
      "instanceUrl": "/instance/vps_01hxa3b4c5d6e7f8g9h0j1k2m3",
      "placementSet": "b",
      "status": "migrating",
      "addedAt": "2026-06-28T10:02:00.000Z"
    }
  ],
  "actions": {
    "canRename": {
      "allowed": true,
      "reason": null
    },
    "canDelete": {
      "allowed": true,
      "reason": null
    },
    "canAddMember": {
      "allowed": true,
      "reason": null
    },
    "canResolve": {
      "allowed": false,
      "reason": "not_needed"
    }
  },
  "createdAt": "2026-06-28T10:00:00.000Z",
  "updatedAt": "2026-06-28T10:05:00.000Z"
}
```

#### 400 - `acceptRestart` was missing or not `true`. `code` is `invalid_request`.
```json
{
  "type": "https://developer.hostup.se/errors/invalid_request",
  "title": "Invalid request",
  "status": 400,
  "detail": "`acceptRestart` must be `true` to confirm the short downtime of one server.",
  "code": "invalid_request",
  "instance": "/api/v2/placement-groups/pg_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/resolve",
  "requestId": "00000000-0000-0000-0000-000000000000",
  "timestamp": "2026-06-28T10:05:00.000Z",
  "errors": [
    {
      "pointer": "/acceptRestart",
      "detail": "`acceptRestart` must be `true` to confirm the short downtime of one server.",
      "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 - The signed-in contact does not have access to the VPS that would be restarted. `code` is `contact_permission_required`.
```json
{
  "type": "https://developer.hostup.se/errors/contact_permission_required",
  "title": "Not allowed",
  "status": 403,
  "detail": "Your contact account does not have access to the server that needs to be restarted.",
  "code": "contact_permission_required",
  "instance": "/api/v2/placement-groups/pg_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/resolve",
  "requestId": "00000000-0000-0000-0000-000000000000",
  "timestamp": "2026-06-28T10:05:00.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"
}
```

#### 409 - The placement group cannot start a restart-based separation right now — nothing needs fixing, a move is already in progress, or no separate hardware is available. `code` is `resolve_not_available`.
```json
{
  "type": "https://developer.hostup.se/errors/resolve_not_available",
  "title": "Nothing to resolve",
  "status": 409,
  "detail": "This placement group has no separation issue that can be resolved with a restart right now.",
  "code": "resolve_not_available",
  "instance": "/api/v2/placement-groups/pg_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/resolve",
  "requestId": "00000000-0000-0000-0000-000000000000",
  "timestamp": "2026-06-28T10:05:00.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"
}
```
