## POST /api/v2/vps/{id}/iso/actions/from-url

**Download ISO from URL**

Queue a download of a public ISO URL into the VPS owner ISO library. The URL must be HTTP or HTTPS, must not redirect, and the file must be at most 20 GB when the server can determine size. After the operation completes, re-read `GET /api/v2/vps/{id}/iso` and mount the returned `available[].id`.

### Related Endpoints

- `POST /api/v2/vps/{id}/iso/actions/mount`: Mount ISO on VPS
- `POST /api/v2/vps/{id}/iso/actions/unmount`: Unmount VPS ISO
- `POST /api/v2/vps/{id}/iso/actions/attach-empty`: Attach empty CD/DVD device

### Headers

- `Accept`: application/json
- `Authorization`: Bearer YOUR_API_KEY
- Required API scopes: `write:vm`, `write:storage`
- `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`

### Request Body

- `url` (string, required) Example: `https://example.com/downloads/ubuntu-24.04-live-server-amd64.iso`
- `filename` (string, required) Example: `ubuntu-24.04-live-server-amd64.iso`
- `decompress` (string, optional) Example: `none`
  Allowed values: none, gzip, lzo, zstd, bzip2

### Request Examples

#### Queue ISO download

```bash
curl -X POST "https://cloud.hostup.se/api/v2/vps/vps_01hxa3b4c5d6e7f8g9h0j1k2m3/iso/actions/from-url" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/downloads/ubuntu-24.04-live-server-amd64.iso",
    "filename": "ubuntu-24.04-live-server-amd64.iso",
    "decompress": "none"
  }'
```

```json
{
  "url": "https://example.com/downloads/ubuntu-24.04-live-server-amd64.iso",
  "filename": "ubuntu-24.04-live-server-amd64.iso",
  "decompress": "none"
}
```

### Response Schema

- `operation` (object, required)
- `operation.status` (string, required) Example: `completed`
  Allowed values: completed
- `operation.jobId` (string, required) Example: `job_01hxa3b4c5d6e7f8g9h0j1k2m3`
- `operation.pollUrl` (string,null, required) Example: `null`

### Responses

#### 200 - ISO file already exists and is ready to use.
```json
{
  "operation": {
    "status": "completed",
    "jobId": "job_01hxa3b4c5d6e7f8g9h0j1k2m3",
    "pollUrl": null
  }
}
```

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