# Containers

**Page:** api/containers

[Download Raw Markdown](./api/containers.md)

---

{/* AUTO-GENERATED — Do not edit manually. Regenerate with: npm run docs:api:generate */}



The Containers API provides endpoints for listing, creating, retrieving, updating, authorizing, and deleting container resources across your projects. Use these endpoints to manage container lifecycle, fetch real-time runtime and resource statistics, and issue offline-verifiable authorization claims for container programs.

## List containers

### `GET /api/v1/containers/`

Get all containers across all projects for the current user with pagination, filtering, and sorting. This endpoint provides a global view of all containers without being scoped to a specific project.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `page` | query | number | No | Page number for pagination - starts from 1 |
| `limit` | query | number | No | Number of containers to return per page - maximum 100 items |
| `sort_by` | query | string | No | Field to sort containers by. Allowed values: `id`, `name`, `status`, `created_at`, `updated_at` |
| `sort_order` | query | string | No | Sort direction - ascending or descending. Allowed values: `asc`, `desc` |
| `realm_id` | query | string | No | Filter by realm ID. Only returns containers that belong to this realm. Alternative to using realm subdomain in URL. |
| `runtime` | query | string | No | Include live runtime information. Accepts "true", "false", or a URL-encoded JSON string like `{"displays":true}`. An empty JSON object `{}` fetches all info. Results are cached for 2 seconds to prevent abuse. |
| `include_proxy_domains` | query | string | No | Include proxy domains (aliases) for each container. When true, adds a proxy_domains array to each container object. Allowed values: `true`, `false` |
| `include_prespawn` | query | string | No | Include prespawn containers in the listing. By default, prespawn containers are excluded from results. Allowed values: `true`, `false` |
| `include_expired` | query | string | No | Include containers that have expired due to server termination. By default, expired containers are excluded from results. Allowed values: `true`, `false` |
| `include_deleting` | query | string | No | Include containers currently being deleted. By default, deleting containers are excluded from results. Allowed values: `true`, `false` |
| `include_proxy_permissions` | query | string | No | Include the full proxy-permissions documents (container-level proxy_permissions and parent-project-level project_proxy_permissions) for each container. Returns proxy authentication group configuration including credentials — request only when explicitly needed. Auth tokens additionally require the resources.proxy_aliases permission. |



```bash
curl -X GET "https://api.hoody.icu/api/v1/containers/?page=1&limit=50&sort_by=created_at&sort_order=desc" \
  -H "Authorization: Bearer <token>"
```


```typescript
const containers = await client.api.containers.listIterator({
  page: 1,
  limit: 50,
  sort_by: "created_at",
  sort_order: "desc"
});
```


```json
{
  "statusCode": 200,
  "message": "Containers retrieved successfully",
  "data": {
    "containers": [
      {
        "id": "507f1f77bcf86cd799439011",
        "project_id": "507f1f77bcf86cd799439033",
        "project_alias": "Production Environment",
        "server_id": "507f1f77bcf86cd799439044",
        "server_name": "node-sg-sin-1",
        "subserver_name": "node-sg-sin-1",
        "name": "web-app-1",
        "color": "#3B82F6",
        "container_image": "ubuntu/24.04",
        "ai": true,
        "hoody_kit": true,
        "dev_kit": true,
        "autostart": true,
        "ramdisk": true,
        "prespawn": false,
        "is_default": false,
        "status": "running",
        "environment_vars": {
          "NODE_ENV": "production"
        },
        "volumes": {},
        "ssh_public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...",
        "comment": "Primary web application container",
        "source_container_id": null,
        "server_expired": false,
        "server_expired_at": null,
        "server_expired_reason": null,
        "created_at": "2025-01-15T10:30:00.000Z",
        "updated_at": "2025-01-15T10:30:00.000Z",
        "realm_ids": [],
        "snapshot_count": 3,
        "last_used_snapshot": "backup-2025-01-14",
        "pool_id": null,
        "proxy_domains": [
          {
            "id": "65f1c2a9b8d7e4f3a2b1c0d9",
            "alias": "my-app",
            "program": "webview",
            "index": 0,
            "target_path": null,
            "allow_path_override": false,
            "expires_at": null,
            "enabled": true,
            "created_at": "2025-01-15T10:30:00.000Z",
            "updated_at": "2025-01-15T10:30:00.000Z",
            "url": null
          }
        ]
      }
    ],
    "pagination": {
      "total": 5,
      "page": 1,
      "limit": 50,
      "totalPages": 1
    }
  }
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid parameter value"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input parameters | One or more request parameters failed validation | Check the error message for specific field requirements and correct your input |
| `INVALID_PARAMETER_VALUE` | Invalid parameter value | A parameter value is outside the allowed range or format | Ensure parameter values meet the documented constraints (min/max, format, regex) |


```json
{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "Authentication token required"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_TOKEN` | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as "Bearer &lt;token&gt;" |
| `INVALID_TOKEN` | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
| `TOKEN_EXPIRED` | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |


```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Insufficient permissions"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
| `ACCOUNT_BANNED` | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |



## List project containers

### `GET /api/v1/projects/{id}/containers`

Get all containers for a specific project with pagination, filtering, and sorting.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `id` | path | string | Yes | Project ID |
| `page` | query | number | No | Page number for pagination |
| `limit` | query | number | No | Number of containers to return per page |
| `sort_by` | query | string | No | Field to sort containers by. Allowed values: `id`, `name`, `status`, `created_at`, `updated_at` |
| `sort_order` | query | string | No | Sort direction. Allowed values: `asc`, `desc` |
| `runtime` | query | string | No | Include live runtime information. Accepts "true", "false", or a URL-encoded JSON string like `{"displays":true}`. An empty JSON object `{}` fetches all info. Results are cached for 2 seconds to prevent abuse. |
| `include_proxy_domains` | query | string | No | Include proxy domains (aliases) for each container. When true, adds a proxy_domains array to each container object. Allowed values: `true`, `false` |
| `include_prespawn` | query | string | No | Include prespawn containers in the listing. By default, prespawn containers are excluded. Allowed values: `true`, `false` |
| `include_deleting` | query | string | No | Include containers currently being deleted. By default, deleting containers are excluded from results. Allowed values: `true`, `false` |
| `include_proxy_permissions` | query | string | No | Include the full proxy-permissions documents (container-level proxy_permissions and parent-project-level project_proxy_permissions) for each container. Returns proxy authentication group configuration including credentials — request only when explicitly needed. Auth tokens additionally require the resources.proxy_aliases permission. |



```bash
curl -X GET "https://api.hoody.icu/api/v1/projects/507f1f77bcf86cd799439011/containers?page=1&limit=20" \
  -H "Authorization: Bearer <token>"
```


```typescript
const containers = await client.api.containers.listByProjectIterator({
  id: "507f1f77bcf86cd799439011",
  page: 1,
  limit: 20
});
```


```json
{
  "statusCode": 200,
  "message": "Containers retrieved successfully",
  "data": {
    "containers": [
      {
        "id": "507f1f77bcf86cd799439013",
        "project_id": "507f1f77bcf86cd799439011",
        "project_alias": "my-web-app",
        "server_id": "507f1f77bcf86cd799439014",
        "server_name": "node-us-nyc-1",
        "name": "frontend-prod",
        "color": "#3B82F6",
        "container_image": "ubuntu/22.04",
        "ai": true,
        "hoody_kit": true,
        "dev_kit": true,
        "autostart": true,
        "prespawn": false,
        "is_default": false,
        "status": "running",
        "environment_vars": {
          "NODE_ENV": "production",
          "PORT": "3000"
        },
        "volumes": {},
        "ssh_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl user@host",
        "comment": "Production frontend server",
        "created_at": "2025-01-15T10:30:00.000Z",
        "updated_at": "2025-01-15T14:22:00.000Z",
        "realm_ids": [],
        "snapshot_count": 3,
        "last_used_snapshot": "before-upgrade",
        "runtime_info": null,
        "pool_id": null,
        "proxy_domains": []
      }
    ],
    "pagination": {
      "total": 42,
      "page": 1,
      "limit": 20,
      "totalPages": 3
    }
  }
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Validation failed"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input parameters | One or more request parameters failed validation | Check the error message for specific field requirements and correct your input |
| `INVALID_ID_FORMAT` | Invalid ID format | The provided ID must be a 24-character hexadecimal string | Ensure the ID is exactly 24 characters long and contains only hexadecimal characters (0-9, a-f) |


```json
{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "Authentication token required"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_TOKEN` | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as "Bearer &lt;token&gt;" |
| `INVALID_TOKEN` | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
| `TOKEN_EXPIRED` | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |


```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Insufficient permissions"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
| `ACCOUNT_BANNED` | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |


```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Resource not found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `RESOURCE_NOT_FOUND` | Resource not found | The requested resource does not exist or has been deleted | Verify the resource ID and ensure it exists |



## Get a container by ID

### `GET /api/v1/containers/{id}`

Retrieve a single container by its identifier, with optional live runtime information and proxy domain details.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `id` | path | string | Yes | Unique identifier of the container to retrieve |
| `runtime` | query | string | No | Include live runtime information. Accepts "true", "false", or a URL-encoded JSON string like `{"displays":true}`. An empty JSON object `{}` fetches all info. Results are cached for 2 seconds to prevent abuse. |
| `include_proxy_domains` | query | string | No | Include proxy domains (aliases) for this container. When true, adds a proxy_domains array to the container object. Allowed values: `true`, `false` |
| `include_proxy_permissions` | query | string | No | Include the full proxy-permissions documents (container-level proxy_permissions and parent-project-level project_proxy_permissions) for each container. Returns proxy authentication group configuration including credentials — request only when explicitly needed. Auth tokens additionally require the resources.proxy_aliases permission. |



```bash
curl -X GET "https://api.hoody.icu/api/v1/containers/507f1f77bcf86cd799439011?include_proxy_domains=true" \
  -H "Authorization: Bearer <token>"
```


```typescript
const container = await client.api.containers.get({
  id: "507f1f77bcf86cd799439011",
  include_proxy_domains: "true"
});
```


```json
{
  "statusCode": 200,
  "message": "Container retrieved successfully",
  "data": {
    "id": "507f1f77bcf86cd799439011",
    "project_id": "507f1f77bcf86cd799439033",
    "project_alias": "Production Environment",
    "server_id": "507f1f77bcf86cd799439044",
    "server_name": "node-sg-sin-1",
    "subserver_name": "node-sg-sin-1",
    "name": "web-app-1",
    "color": "#3B82F6",
    "container_image": "ubuntu/24.04",
    "ai": true,
    "hoody_kit": true,
    "dev_kit": true,
    "autostart": true,
    "ramdisk": true,
    "prespawn": false,
    "is_default": false,
    "status": "running",
    "environment_vars": {
      "NODE_ENV": "production"
    },
    "volumes": {},
    "ssh_public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...",
    "comment": "Primary web application container",
    "source_container_id": null,
    "server_expired": false,
    "server_expired_at": null,
    "server_expired_reason": null,
    "created_at": "2025-01-15T10:30:00.000Z",
    "updated_at": "2025-01-15T10:30:00.000Z",
    "realm_ids": [],
    "snapshot_count": 3,
    "last_used_snapshot": "backup-2025-01-14",
    "warnings": [],
    "pool_id": null,
    "proxy_domains": []
  }
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid ID format"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INVALID_ID_FORMAT` | Invalid ID format | The provided ID must be a 24-character hexadecimal string | Ensure the ID is exactly 24 characters long and contains only hexadecimal characters (0-9, a-f) |


```json
{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "Authentication token required"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_TOKEN` | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as "Bearer &lt;token&gt;" |
| `INVALID_TOKEN` | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
| `TOKEN_EXPIRED` | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |


```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Insufficient permissions"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
| `ACCOUNT_BANNED` | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |


```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Container not found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `CONTAINER_NOT_FOUND` | Container not found | The requested container does not exist or you do not have permission to access it. | Verify the container ID is correct and that you have access to the project it belongs to. |



## Get container resource statistics

### `GET /api/v1/containers/{id}/stats`

Get real-time resource usage statistics for a container including CPU, memory, disk, and network metrics. Useful for monitoring performance and troubleshooting resource issues.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `id` | path | string | Yes | Unique identifier of the container |



```bash
curl -X GET "https://api.hoody.icu/api/v1/containers/507f1f77bcf86cd799439011/stats" \
  -H "Authorization: Bearer <token>"
```


```typescript
const stats = await client.api.containers.getStats({
  id: "507f1f77bcf86cd799439011"
});
```


```json
{
  "statusCode": 200,
  "message": "Container statistics retrieved successfully",
  "data": {
    "id": "507f1f77bcf86cd799439011",
    "project_id": "507f1f77bcf86cd799439033",
    "project_name": "Production Environment",
    "server_name": "node-sg-sin-1",
    "subserver_name": "node-sg-sin-1",
    "status": "Running",
    "status_code": 103,
    "processes": 143,
    "started_at": "2025-12-03T18:39:53.938688987Z",
    "cpu": {
      "usage": 17303605000,
      "allocated_time": 24000000000,
      "usage_percent": 72.1
    },
    "memory": {
      "usage": 1474666496,
      "total": 131503332000,
      "usage_percent": 1.12,
      "swap_usage": 0,
      "swap_usage_peak": 0,
      "usage_peak": 0
    },
    "disk": {
      "root": {
        "total": 0,
        "usage": 11081670656
      }
    },
    "network": [
      {
        "interface": "eth0",
        "addresses": [
          {
            "address": "10.10.0.122",
            "family": "inet",
            "netmask": "30",
            "scope": "global"
          }
        ],
        "counters": {
          "bytes_received": 1098069936,
          "bytes_sent": 16777319,
          "packets_received": 346440,
          "packets_sent": 242010,
          "errors_received": 0,
          "errors_sent": 0,
          "packets_dropped_inbound": 0,
          "packets_dropped_outbound": 0
        },
        "state": "up",
        "type": "broadcast"
      }
    ],
    "processing_time": "3ms"
  }
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid ID format"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INVALID_ID_FORMAT` | Invalid ID format | The provided ID must be a 24-character hexadecimal string | Ensure the ID is exactly 24 characters long and contains only hexadecimal characters (0-9, a-f) |


```json
{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "Authentication token required"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_TOKEN` | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as "Bearer &lt;token&gt;" |
| `INVALID_TOKEN` | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
| `TOKEN_EXPIRED` | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |


```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Insufficient permissions"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
| `ACCOUNT_BANNED` | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
| `RESOURCE_ACCESS_DENIED` | Resource access denied | You do not have permission to access this specific resource | Ensure you own this resource or have been granted access by the owner |


```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Container not found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `CONTAINER_NOT_FOUND` | Container not found | The requested container does not exist or you do not have permission to access it. | Verify the container ID is correct and that you have access to the project it belongs to. |
| `RESOURCE_NOT_FOUND` | Resource not found | The requested resource does not exist or has been deleted | Verify the resource ID and ensure it exists |


```json
{
  "statusCode": 500,
  "error": "Internal Server Error",
  "message": "An unexpected error occurred"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INTERNAL_SERVER_ERROR` | Internal server error | An unexpected error occurred on the server | Try again later, or contact support if the problem persists |
| `EXTERNAL_SERVICE_ERROR` | External service error | A required external service is unavailable or returned an error | Try again later when the external service is available |



## Authorize container access

### `POST /api/v1/containers/{id}/authorize`

Issues a signed, portable container authorization claim. The returned `container_claim` is an ED25519-signed credential that proves the user identity, the authorized container, and the issue time.

Container programs can verify this claim **offline** using Hoody's public key at `GET /api/v1/meta/public-key` — no API round-trip is needed during verification. Claims expire after the configured expiry (default 1h); clients should re-call this endpoint to refresh before expiry.


The response also includes the `X-Hoody-Signature` header, which contains an ED25519 signature of the response body in the format `t=&lt;unix_ts&gt;,kid=&lt;keyId&gt;,path=&lt;urlPath&gt;,sig=&lt;128-hex&gt;`.


#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `id` | path | string | Yes | Container ID (24-char hex) |



```bash
curl -X POST "https://api.hoody.icu/api/v1/containers/507f1f77bcf86cd799439011/authorize" \
  -H "Authorization: Bearer <token>"
```


```typescript
const claim = await client.api.containers.authorize({
  id: "507f1f77bcf86cd799439011"
});
```


```json
{
  "statusCode": 200,
  "message": "Container authorization claim issued",
  "data": {
    "container_claim": {
      "kid": "v1",
      "payload_b64": "eyJjbGFpbV90eXBlIjoiY29udGFpbmVyIiwi...",
      "signature_hex": "a1b2c3d4..."
    },
    "expires_in": 3600,
    "container_id": "507f1f77bcf86cd799439011",
    "project_id": "507f1f77bcf86cd799439033"
  }
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid ID format"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INVALID_ID_FORMAT` | Invalid ID format | The provided ID must be a 24-character hexadecimal string | Ensure the ID is exactly 24 characters long and contains only hexadecimal characters (0-9, a-f) |


```json
{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "Authentication token required"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_TOKEN` | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as "Bearer &lt;token&gt;" |


```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Insufficient permissions"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |


```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Container not found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `CONTAINER_NOT_FOUND` | Container not found | The requested container does not exist or you do not have permission to access it. | Verify the container ID is correct and that you have access to the project it belongs to. |


```json
{
  "statusCode": 503,
  "error": "SIGNING_NOT_CONFIGURED",
  "message": "Response signing is not configured on this API instance"
}
```



## Create a container

### `POST /api/v1/projects/{id}/containers`

Create a new container within a project. The container will be provisioned on the specified server.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `id` | path | string | Yes | Project ID |

#### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `server_id` | string | Yes | ID of the server to host the container |
| `name` | string | No | Name for the container. Must be 3-100 characters, alphanumeric with hyphens and underscores. Omit or use "rand" to generate a random name. |
| `color` | string | No | HEX color for the container (e.g., #FF0000 or FF0000). If not provided, a random color will be generated. The # prefix will be added automatically if missing, and the color will be converted to uppercase. |
| `container_image` | string | No | Container image to use. If null or not provided, will use the default configured image. |
| `ai` | boolean | No | Whether AI features are enabled. Default: `true` |
| `environment_vars` | object | No | Environment variables to set in the container. Keys must match `^[a-zA-Z_][a-zA-Z0-9_]*$`. Max 200 properties, each value &le; 65536 chars. |
| `ssh_public_key` | string | No | SSH public key for container access. SSH public keys must be unique per container (one container per key). If not provided, will inherit from project defaults. |
| `comment` | string | No | Optional comment for the container (max 16000 characters) |
| `hoody_kit` | boolean | No | Enable all Hoody Kit features (extra-apt-sources, basic-packages, hoody-daemon, sudo-env, remove-snapd, webview, user, hoody-ai, ttyd). Default: `true` |
| `dev_kit` | boolean | No | Enable dev_kit development tools in the container. Defaults to true when hoody_kit is true, false when hoody_kit is false (unless explicitly set). Cannot be updated after creation. |
| `autostart` | boolean | No | Whether the container should start automatically on host boot. Default: `true` |
| `ramdisk` | boolean | No | Whether to mount a ramdisk at /ramdisk in the container. Default: `true` |
| `cache` | boolean | No | Enable use of cached images during container creation. Default: `true` |
| `cache_image` | boolean | No | Force the creation of a new cached image from the container image. Default: `false` |
| `prespawn` | boolean | No | Create container as prespawn cache. Prespawn containers are excluded from default listings and quota counts. Default: `false` |
| `bypass_prespawn` | boolean | No | Bypass prespawn container claiming and create a fresh container directly. Default: `false` |
| `realm_ids` | array | No | Realm IDs to assign this container to. Containers can have different realm membership than their parent project. |



```bash
curl -X POST "https://api.hoody.icu/api/v1/projects/507f1f77bcf86cd799439011/containers" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "server_id": "507f1f77bcf86cd799439014",
    "name": "backend-api",
    "color": "#10B981",
    "container_image": "ubuntu/22.04",
    "ai": true,
    "environment_vars": {
      "DATABASE_URL": "postgresql://user:pass@db:5432/app",
      "REDIS_URL": "redis://cache:6379"
    },
    "autostart": true,
    "ramdisk": true
  }'
```


```typescript
const container = await client.api.containers.create({
  id: "507f1f77bcf86cd799439011",
  data: {
    server_id: "507f1f77bcf86cd799439014",
    name: "backend-api",
    color: "#10B981",
    container_image: "ubuntu/22.04",
    environment_vars: {
      DATABASE_URL: "postgresql://user:pass@db:5432/app",
      REDIS_URL: "redis://cache:6379"
    }
  }
});
```


```json
{
  "statusCode": 201,
  "message": "Container created successfully",
  "data": {
    "id": "507f1f77bcf86cd799439015",
    "project_id": "507f1f77bcf86cd799439011",
    "project_alias": "my-web-app",
    "server_id": "507f1f77bcf86cd799439014",
    "server_name": "node-us-nyc-1",
    "subserver_name": "node-us-nyc-1",
    "name": "backend-api",
    "color": "#10B981",
    "container_image": "ubuntu/22.04",
    "ai": true,
    "hoody_kit": true,
    "dev_kit": true,
    "autostart": true,
    "prespawn": false,
    "status": "creating",
    "environment_vars": {
      "DATABASE_URL": "postgresql://user:pass@db:5432/app",
      "REDIS_URL": "redis://cache:6379"
    },
    "volumes": {},
    "ssh_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl user@host",
    "comment": "Backend API server with PostgreSQL connection",
    "created_at": "2025-01-15T15:45:00.000Z",
    "updated_at": "2025-01-15T15:45:00.000Z",
    "realm_ids": []
  }
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Validation failed"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input parameters | One or more request parameters failed validation | Check the error message for specific field requirements and correct your input |
| `INVALID_ID_FORMAT` | Invalid ID format | The provided ID must be a 24-character hexadecimal string | Ensure the ID is exactly 24 characters long and contains only hexadecimal characters (0-9, a-f) |
| `INVALID_CONTAINER_NAME` | Invalid container name | Container name must be 3-100 characters, alphanumeric with hyphens and underscores. | Use a valid name between 3 and 100 characters containing only a-z, A-Z, 0-9, -, and _. |
| `SERVER_CONTAINER_LIMIT` | Server container limit reached | The target server is at its maximum number of live containers (explicit max_containers, or the free-tier default). | Delete an existing container on this server, or create the container on a different server. |


```json
{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "Authentication token required"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_TOKEN` | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as "Bearer &lt;token&gt;" |
| `INVALID_TOKEN` | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
| `TOKEN_EXPIRED` | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |


```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Insufficient permissions"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
| `ACCOUNT_BANNED` | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |


```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Resource not found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `RESOURCE_NOT_FOUND` | Resource not found | The requested resource does not exist or has been deleted | Verify the resource ID and ensure it exists |


```json
{
  "statusCode": 409,
  "error": "Conflict",
  "message": "Container name already in use within the project"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `CONTAINER_NAME_IN_USE` | Container name already in use | A container with this name already exists in the project. | Choose a different name for your container. |
| `SSH_PUBLIC_KEY_IN_USE` | SSH public key already in use | SSH public keys must be unique per container. A single public key cannot be assigned to multiple containers because it is used for routing SSH connections. | Generate a new SSH key pair for this container, or remove the key from the other container before reusing it. |


```json
{
  "statusCode": 422,
  "error": "Unprocessable Entity",
  "message": "Quota exceeded"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `QUOTA_EXCEEDED` | Quota exceeded | You have exceeded your quota for this resource type | Delete unused resources or upgrade your plan for higher limits |



## Update a container

### `PATCH /api/v1/containers/{id}`

Update mutable properties of an existing container. Only fields provided in the request body are modified.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `id` | path | string | Yes | Unique identifier of the container to update |

#### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | No | Human-readable name for the container - must be unique within the project. 1-100 characters. |
| `color` | string | No | HEX color for the container (e.g., #FF0000 or FF0000). The # prefix will be added automatically if missing, and the color will be converted to uppercase. |
| `ai` | boolean | No | Whether AI features are enabled. If omitted, the current value is preserved. |
| `autostart` | boolean | No | Whether the container starts automatically on host boot. If omitted, the current value is preserved. |
| `ramdisk` | boolean | No | Whether to mount a ramdisk at /ramdisk in the container. If omitted, the current value is preserved. |
| `environment_vars` | object | No | Environment variables to set in the container as key-value pairs. Max 200 properties. |
| `ssh_public_key` | string \| null | No | SSH public key for container access. SSH public keys must be unique per container. Re-sending the same key is a no-op. Set to null to clear or inherit from project defaults. |
| `comment` | string \| null | No | Optional comment for the container (max 16000 characters). Set to null to clear existing comment. |
| `realm_ids` | array | No | Update realm membership. Only unrestricted tokens and admin users can modify realm_ids. |



```bash
curl -X PATCH "https://api.hoody.icu/api/v1/containers/507f1f77bcf86cd799439011" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "web-app-prod",
    "color": "#10B981",
    "ai": true,
    "comment": "Updated production web app"
  }'
```


```typescript
const container = await client.api.containers.update({
  id: "507f1f77bcf86cd799439011",
  data: {
    name: "web-app-prod",
    color: "#10B981",
    comment: "Updated production web app"
  }
});
```


```json
{
  "statusCode": 200,
  "message": "Container updated successfully",
  "data": {
    "id": "507f1f77bcf86cd799439011",
    "project_id": "507f1f77bcf86cd799439033",
    "project_alias": "Production Environment",
    "server_id": "507f1f77bcf86cd799439044",
    "server_name": "node-sg-sin-1",
    "subserver_name": "node-sg-sin-1",
    "name": "web-app-prod",
    "color": "#10B981",
    "container_image": "ubuntu/24.04",
    "ai": true,
    "hoody_kit": true,
    "dev_kit": true,
    "autostart": true,
    "ramdisk": true,
    "prespawn": false,
    "is_default": false,
    "status": "running",
    "environment_vars": {
      "NODE_ENV": "production"
    },
    "volumes": {},
    "ssh_public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...",
    "comment": "Updated production web app",
    "source_container_id": null,
    "created_at": "2025-01-15T10:30:00.000Z",
    "updated_at": "2025-01-16T09:00:00.000Z",
    "realm_ids": [],
    "pool_id": null
  }
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Validation failed"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid input parameters | One or more request parameters failed validation | Check the error message for specific field requirements and correct your input |
| `INVALID_ID_FORMAT` | Invalid ID format | The provided ID must be a 24-character hexadecimal string | Ensure the ID is exactly 24 characters long and contains only hexadecimal characters (0-9, a-f) |
| `INVALID_CONTAINER_NAME` | Invalid container name | Container name must be 3-100 characters, alphanumeric with hyphens and underscores. | Use a valid name between 3 and 100 characters containing only a-z, A-Z, 0-9, -, and _. |


```json
{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "Authentication token required"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_TOKEN` | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as "Bearer &lt;token&gt;" |
| `INVALID_TOKEN` | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
| `TOKEN_EXPIRED` | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |


```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Insufficient permissions"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
| `ACCOUNT_BANNED` | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
| `OPERATION_NOT_PERMITTED_ON_EXPIRED` | Operation Not Permitted on Expired Container | This operation cannot be performed because the container has expired due to server termination. | The container is in a read-only state. No further operations are allowed. Please create a new container. |


```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Container not found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `CONTAINER_NOT_FOUND` | Container not found | The requested container does not exist or you do not have permission to access it. | Verify the container ID is correct and that you have access to the project it belongs to. |
| `RESOURCE_NOT_FOUND` | Resource not found | The requested resource does not exist or has been deleted | Verify the resource ID and ensure it exists |


```json
{
  "statusCode": 409,
  "error": "Conflict",
  "message": "Container name already in use within the project"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `CONTAINER_NAME_IN_USE` | Container name already in use | A container with this name already exists in the project. | Choose a different name for your container. |
| `SSH_PUBLIC_KEY_IN_USE` | SSH public key already in use | SSH public keys must be unique per container. A single public key cannot be assigned to multiple containers because it is used for routing SSH connections. | Generate a new SSH key pair for this container, or remove the key from the other container before reusing it. |



## Delete a container

### `DELETE /api/v1/containers/{id}`

Delete a container. The container will be marked for deletion and removed asynchronously.


This action is irreversible. All data inside the container will be lost unless preserved by a snapshot.


#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `id` | path | string | Yes | Unique identifier of the container to delete |



```bash
curl -X DELETE "https://api.hoody.icu/api/v1/containers/507f1f77bcf86cd799439011" \
  -H "Authorization: Bearer <token>"
```


```typescript
await client.api.containers.delete({
  id: "507f1f77bcf86cd799439011"
});
```


```json
{
  "statusCode": 200,
  "message": "Container deleted successfully"
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid ID format"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INVALID_ID_FORMAT` | Invalid ID format | The provided ID must be a 24-character hexadecimal string | Ensure the ID is exactly 24 characters long and contains only hexadecimal characters (0-9, a-f) |


```json
{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "Authentication token required"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_TOKEN` | Authentication token missing | No authentication token was provided in the request | Include a valid JWT token in the Authorization header as "Bearer &lt;token&gt;" |
| `INVALID_TOKEN` | Invalid authentication token | The provided authentication token is malformed or invalid | Obtain a new token by logging in again or using a valid auth token |
| `TOKEN_EXPIRED` | Authentication token expired | The provided authentication token has expired | Obtain a new token by logging in again or refreshing your session |


```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Insufficient permissions"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | You do not have the required permissions to perform this action | Contact the resource owner or administrator to request access |
| `ACCOUNT_BANNED` | Account banned | Your account has been banned and cannot access this resource | Contact support for information about your account status |
| `OPERATION_NOT_PERMITTED_ON_EXPIRED` | Operation Not Permitted on Expired Container | This operation cannot be performed because the container has expired due to server termination. | The container is in a read-only state. No further operations are allowed. Please create a new container. |


```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Container not found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `CONTAINER_NOT_FOUND` | Container not found | The requested container does not exist or you do not have permission to access it. | Verify the container ID is correct and that you have access to the project it belongs to. |


```json
{
  "statusCode": 409,
  "error": "Conflict",
  "message": "Resource is currently in use"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `RESOURCE_IN_USE` | Resource in use | This resource cannot be modified or deleted because it is currently in use | Stop using the resource or remove dependent resources first |
| `OPERATION_STATE_CONFLICT` | Container State Conflict | The operation cannot be performed because the container is not in the correct state. | Check the container's current status. For example, a container must be stopped to be started. |


```json
{
  "statusCode": 500,
  "error": "Internal Server Error",
  "message": "An unexpected error occurred"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INTERNAL_SERVER_ERROR` | Internal server error | An unexpected error occurred on the server | Try again later, or contact support if the problem persists |
| `EXTERNAL_SERVICE_ERROR` | External service error | A required external service is unavailable or returned an error | Try again later when the external service is available |