## GET /api/v2/vps/{id}/details

**Get detailed VPS state**

Return detailed VPS state including resources, billing, bandwidth, IPs, power state, SSH keys, login metadata, action gates, and overdue invoice context. Use this when an API agent needs operational context beyond the lightweight `GET /api/v2/vps/{id}` summary. Inspect `billing.isPayg` before choosing a change flow: fixed-cycle VPS instances use plan upgrade/billing-cycle endpoints when the relevant action gate allows it; PAYG Cloud VPS instances scale through configurable resource changes instead.

### Related Endpoints

- `GET /api/v2/vps/{id}`: Get VPS details
- `GET /api/v2/vps/{id}/iso`: List VPS ISO media
- `GET /api/v2/vps/{id}/disks`: List VPS disks

### Headers

- `Accept`: application/json
- `Authorization`: Bearer YOUR_API_KEY
- Required API scope: `read:vm`

### Parameters

- `id` (path, string, required): Public VPS ID. Get it 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`

### Request Example

```bash
curl -X GET "https://cloud.hostup.se/api/v2/vps/vps_01hxa3b4c5d6e7f8g9h0j1k2m3/details" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
```

### Response Schema

- `id` (string, required) Example: `vps_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `productName` (string,null, required) Example: `VPS XS`
- `hostname` (string,null, required) Example: `web-01.example.com`
- `serviceStatus` (string, required) Example: `active`
  Allowed values: active, pending, suspended, terminated, cancelled, unknown
- `createdAt` (string,null, required) Example: `2026-04-27T12:00:00.000Z`
- `nextDueAt` (string,null, required) Example: `2026-05-27T00:00:00.000Z`
- `billing` (object, required)
- `billing.amount` (number, required) Example: `99`
- `billing.currencyCode` (string, required) Example: `SEK`
- `billing.billingCycle` (string, required) Example: `monthly`
  Allowed values: monthly, quarterly, semiannually, annually, biennially, triennially, free
- `billing.isPayg` (boolean, required) Example: `false`
- `cpuCores` (number, required) Example: `2`
- `memoryGb` (number, required) Example: `4`
- `storageGb` (number, required) Example: `80`
- `backupsIncluded` (integer, required) Example: `2`
- `bandwidth` (object, required)
- `bandwidth.usedGb` (number, required) Example: `12.5`
- `bandwidth.limitGb` (number, required) Example: `1000`
- `bandwidth.inboundGb` (number, required) Example: `4.2`
- `bandwidth.outboundGb` (number, required) Example: `8.3`
- `bandwidth.usagePercent` (number, required) Example: `1.25`
- `bandwidth.hasOverage` (boolean, required) Example: `false`
- `bandwidthUsage` (object, required)
- `bandwidthUsage.dataReceivedGb` (number, required) Example: `4.2`
- `bandwidthUsage.dataSentGb` (number, required) Example: `8.3`
- `usageLog` (array<object>, required)
- `usageLog[].recordedAt` (string, required) Example: `2026-04-27T00:00:00.000Z`
- `usageLog[].dataReceivedGb` (number, required) Example: `0.5`
- `usageLog[].dataSentGb` (number, required) Example: `1`
- `usageLog[].totalGb` (number, required) Example: `1.5`
- `ipAddresses` (array<string>, required)
- `ipv4` (string,null, required) Example: `203.0.113.10`
- `ipv6` (string,null, required) Example: `2001:db8::10`
- `operatingSystem` (object,null, required)
- `powerState` (string,null, required) Example: `running`
  Allowed values: running, stopped, paused, unknown, 
- `operationState` (object, required)
- `operationState.locked` (boolean, required) Example: `false`
- `sshKeys` (array<string>, required)
- `access` (object, required)
- `access.username` (string,null, required) Example: `root`
- `access.rootPassword` (string,null, required) Example: `initial-password-from-panel`
- `pricing` (object,null, required): Deprecated migration-only pricing breakdown. Prefer the canonical `billing` object for amount, currency, and cycle.
- `pinned` (boolean, required) Example: `false`
- `availability` (object, required)
- `availability.available` (boolean, required) Example: `true`
- `availability.reason` (string,null, required) Example: `null`
- `actions` (object, required)
- `actions.canRebuild` (object, required)
- `actions.canRebuild.allowed` (boolean, required) Example: `true`
- `actions.canRebuild.reason` (string,null, required) Example: `null`
- `actions.canRebuild.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canResetPassword` (object, required)
- `actions.canResetPassword.allowed` (boolean, required) Example: `true`
- `actions.canResetPassword.reason` (string,null, required) Example: `null`
- `actions.canResetPassword.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canResetSshKeys` (object, required)
- `actions.canResetSshKeys.allowed` (boolean, required) Example: `true`
- `actions.canResetSshKeys.reason` (string,null, required) Example: `null`
- `actions.canResetSshKeys.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canResizeDisk` (object, required)
- `actions.canResizeDisk.allowed` (boolean, required) Example: `true`
- `actions.canResizeDisk.reason` (string,null, required) Example: `null`
- `actions.canResizeDisk.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canAddDisk` (object, required)
- `actions.canAddDisk.allowed` (boolean, required) Example: `true`
- `actions.canAddDisk.reason` (string,null, required) Example: `null`
- `actions.canAddDisk.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canSnapshot` (object, required)
- `actions.canSnapshot.allowed` (boolean, required) Example: `true`
- `actions.canSnapshot.reason` (string,null, required) Example: `null`
- `actions.canSnapshot.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canBackup` (object, required)
- `actions.canBackup.allowed` (boolean, required) Example: `true`
- `actions.canBackup.reason` (string,null, required) Example: `null`
- `actions.canBackup.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canChangeBillingCycle` (object, required)
- `actions.canChangeBillingCycle.allowed` (boolean, required) Example: `true`
- `actions.canChangeBillingCycle.reason` (string,null, required) Example: `null`
- `actions.canChangeBillingCycle.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canUpgrade` (object, required)
- `actions.canUpgrade.allowed` (boolean, required) Example: `true`
- `actions.canUpgrade.reason` (string,null, required) Example: `null`
- `actions.canUpgrade.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canResize` (object, required)
- `actions.canResize.allowed` (boolean, required) Example: `true`
- `actions.canResize.reason` (string,null, required) Example: `null`
- `actions.canResize.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canDetachIsos` (object, required)
- `actions.canDetachIsos.allowed` (boolean, required) Example: `true`
- `actions.canDetachIsos.reason` (string,null, required) Example: `null`
- `actions.canDetachIsos.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canConvertToCloud` (object, required)
- `actions.canConvertToCloud.allowed` (boolean, required) Example: `true`
- `actions.canConvertToCloud.reason` (string,null, required) Example: `null`
- `actions.canConvertToCloud.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canStart` (object, required)
- `actions.canStart.allowed` (boolean, required) Example: `true`
- `actions.canStart.reason` (string,null, required) Example: `null`
- `actions.canStart.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canStop` (object, required)
- `actions.canStop.allowed` (boolean, required) Example: `true`
- `actions.canStop.reason` (string,null, required) Example: `null`
- `actions.canStop.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canRestart` (object, required)
- `actions.canRestart.allowed` (boolean, required) Example: `true`
- `actions.canRestart.reason` (string,null, required) Example: `null`
- `actions.canRestart.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canShutdown` (object, required)
- `actions.canShutdown.allowed` (boolean, required) Example: `true`
- `actions.canShutdown.reason` (string,null, required) Example: `null`
- `actions.canShutdown.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canReset` (object, required)
- `actions.canReset.allowed` (boolean, required) Example: `true`
- `actions.canReset.reason` (string,null, required) Example: `null`
- `actions.canReset.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canCancel` (object, required)
- `actions.canCancel.allowed` (boolean, required) Example: `true`
- `actions.canCancel.reason` (string,null, required) Example: `null`
- `actions.canCancel.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canToggleAutorenew` (object, required)
- `actions.canToggleAutorenew.allowed` (boolean, required) Example: `true`
- `actions.canToggleAutorenew.reason` (string,null, required) Example: `null`
- `actions.canToggleAutorenew.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canExtendMaintenance` (object, required)
- `actions.canExtendMaintenance.allowed` (boolean, required) Example: `true`
- `actions.canExtendMaintenance.reason` (string,null, required) Example: `null`
- `actions.canExtendMaintenance.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `actions.canCancelJob` (object, required)
- `actions.canCancelJob.allowed` (boolean, required) Example: `true`
- `actions.canCancelJob.reason` (string,null, required) Example: `null`
- `actions.canCancelJob.code` (string,null, optional): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `overdueInvoices` (array<object>, required)
- `overdueInvoices[].id` (string, required) Example: `inv_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `overdueInvoices[].number` (string,null, required) Example: `10001`
- `overdueInvoices[].amount` (number, required) Example: `99`
- `overdueInvoices[].currencyCode` (string, required) Example: `SEK`
- `overdueInvoices[].dueAt` (string,null, required) Example: `2026-05-27T00:00:00.000Z`
- `overdueInvoices[].status` (string, required) Example: `unpaid`
  Allowed values: unpaid, paid, cancelled, refunded, collections, unknown
- `overdueInvoices[].paymentUrl` (string,null, required) Example: `/billing?invoice=10001`

### Responses

#### 200 - Detailed VPS state.
```json
{
  "id": "vps_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "productName": "VPS XS",
  "hostname": "web-01.example.com",
  "serviceStatus": "active",
  "createdAt": "2026-04-27T12:00:00.000Z",
  "nextDueAt": "2026-05-27T00:00:00.000Z",
  "billing": {
    "amount": 99,
    "currencyCode": "SEK",
    "billingCycle": "monthly",
    "isPayg": false
  },
  "cpuCores": 2,
  "memoryGb": 4,
  "storageGb": 80,
  "backupsIncluded": 2,
  "bandwidth": {
    "usedGb": 12.5,
    "limitGb": 1000,
    "inboundGb": 4.2,
    "outboundGb": 8.3,
    "usagePercent": 1.25,
    "hasOverage": false
  },
  "bandwidthUsage": {
    "dataReceivedGb": 4.2,
    "dataSentGb": 8.3
  },
  "usageLog": [
    {
      "recordedAt": "2026-04-27T00:00:00.000Z",
      "dataReceivedGb": 0.5,
      "dataSentGb": 1,
      "totalGb": 1.5
    }
  ],
  "ipAddresses": [
    "203.0.113.10"
  ],
  "ipv4": "203.0.113.10",
  "ipv6": "2001:db8::10",
  "operatingSystem": {
    "displayName": "Ubuntu 24.04",
    "family": "ubuntu",
    "version": "24.04",
    "variant": null
  },
  "powerState": "running",
  "operationState": {
    "locked": false
  },
  "sshKeys": [
    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIexample user@example.com"
  ],
  "access": {
    "username": "root",
    "rootPassword": "initial-password-from-panel"
  },
  "pricing": {
    "currency": "SEK",
    "currencyCode": "SEK",
    "billingCycle": {
      "id": "monthly",
      "months": 1,
      "isFree": false
    },
    "pricePerCycle": 39,
    "baseMonthlyCost": 39,
    "baseAnnualCost": 468,
    "addonsMonthlyCost": 1.5,
    "addonsAnnualCost": 18,
    "totalMonthlyCost": 40.5,
    "totalAnnualCost": 486,
    "addons": [
      {
        "id": "storage-addon",
        "name": "Attachable Block Storage",
        "category": "storage",
        "unit": "GB",
        "included": 50,
        "quantity": 100,
        "unitPriceMonthly": 0.03,
        "monthlyCost": 1.5,
        "annualCost": 18,
        "currencyCode": "SEK"
      }
    ]
  },
  "pinned": false,
  "actions": {
    "canRebuild": {
      "allowed": true,
      "reason": null
    },
    "canResetPassword": {
      "allowed": true,
      "reason": null
    },
    "canResetSshKeys": {
      "allowed": true,
      "reason": null
    },
    "canResizeDisk": {
      "allowed": true,
      "reason": null
    },
    "canAddDisk": {
      "allowed": true,
      "reason": null
    },
    "canSnapshot": {
      "allowed": false,
      "reason": "Snapshot availability could not be confirmed."
    },
    "canBackup": {
      "allowed": false,
      "reason": "Backup availability could not be confirmed."
    },
    "canChangeBillingCycle": {
      "allowed": true,
      "reason": null
    },
    "canUpgrade": {
      "allowed": true,
      "reason": null
    },
    "canResize": {
      "allowed": false,
      "reason": "Resize is a PAYG-only action. Use upgrade for fixed plans."
    },
    "canDetachIsos": {
      "allowed": false,
      "reason": "No ISOs attached."
    },
    "canConvertToCloud": {
      "allowed": false,
      "reason": "Account verification is required before converting to Cloud VM."
    },
    "canStart": {
      "allowed": false,
      "reason": "VPS is already running."
    },
    "canStop": {
      "allowed": true,
      "reason": null
    },
    "canRestart": {
      "allowed": true,
      "reason": null
    },
    "canShutdown": {
      "allowed": true,
      "reason": null
    },
    "canReset": {
      "allowed": true,
      "reason": null
    },
    "canCancel": {
      "allowed": true,
      "reason": null
    },
    "canToggleAutorenew": {
      "allowed": true,
      "reason": null
    },
    "canExtendMaintenance": {
      "allowed": false,
      "reason": "No pending maintenance to extend."
    },
    "canCancelJob": {
      "allowed": false,
      "reason": "No active jobs to cancel."
    }
  },
  "availability": {
    "available": true,
    "reason": null
  },
  "overdueInvoices": []
}
```

#### 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"
}
```
