Container Copy & Sync
Section titled “Container Copy & Sync”The Container Copy & Sync endpoints let you replicate an existing container to another project or server, and then incrementally resync the copy from its source. Both operations run asynchronously: the API returns immediately with the new container state (typically copying), and the copy/sync completes in the background. Once a copy is created, it can be kept up-to-date with the source at any time via the sync endpoint.
Copy a container
Section titled “Copy a container”POST /api/v1/containers/{id}/copy
Section titled “POST /api/v1/containers/{id}/copy”Creates a copy of an existing container. The copy operation runs asynchronously, and the new container starts automatically upon successful completion. The copy can target the same project or a different project on the same or a different server. By default, firewall rules and network rules are not carried over to the copy; use the copy_firewall_rules and copy_network_rules flags to opt in.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Unique identifier of the source container to copy |
Request Body
Section titled “Request Body”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
target_project_id | string | Yes | — | ID of the project where the copy will be created (24-character hexadecimal string) |
target_server_id | string | No | — | ID of the server where the copy will be created (defaults to source server) |
name | string | No | — | Name for the copied container (auto-generated if not provided). 3-100 characters, alphanumeric with hyphens and underscores |
ssh_public_key | string | No | — | SSH public key for the copied container (must be unique, not inherited from source) |
source_snapshot | string | No | — | Specific snapshot to copy from (copies latest state if not provided) |
copy_firewall_rules | boolean | No | false | Whether to copy firewall rules (ACL) from source container to target container |
copy_network_rules | boolean | No | false | Whether to copy network rules/settings from source container to target container |
curl -X POST https://api.hoody.icu/api/v1/containers/507f1f77bcf86cd799439011/copy \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "target_project_id": "507f1f77bcf86cd799439033", "target_server_id": "507f1f77bcf86cd799439044", "name": "web-app-copy", "ssh_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0wmN/CrjJXa/V2gV3L1q8TzX0Y2d5L3p7b6gK4yW1M user@host", "copy_firewall_rules": true, "copy_network_rules": false }'await client.api.containers.copy( "507f1f77bcf86cd799439011", { target_project_id: "507f1f77bcf86cd799439033", target_server_id: "507f1f77bcf86cd799439044", name: "web-app-copy", ssh_public_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0wmN/CrjJXa/V2gV3L1q8TzX0Y2d5L3p7b6gK4yW1M user@host", copy_firewall_rules: true, copy_network_rules: false });{ "statusCode": 201, "message": "Container copy initiated successfully", "data": { "id": "507f1f77bcf86cd799439099", "name": "web-app-copy", "status": "copying", "source_container_id": "507f1f77bcf86cd799439011", "project_id": "507f1f77bcf86cd799439033", "project_alias": "production", "server_id": "507f1f77bcf86cd799439044", "server_name": "node-sg-sin-1", "subserver_name": "node-sg-sin-1", "server": { "name": "node-sg-sin-1", "country": "SG", "country_name": "Singapore", "city": "Singapore", "region": "Asia Pacific", "datacenter": "SIN-DC1", "is_free": true, "specs": { "cpu_cores": null, "ram_gb": null, "disk_gb": 50, "shared_compute": true }, "expires_at": null }, "ssh_hostname": "507f1f77bcf86cd799439033-507f1f77bcf86cd799439099-ssh.node-sg-sin-1.containers.hoody.icu", "color": "#3498db", "container_image": "ubuntu-22.04", "ai": false, "hoody_kit": false, "dev_kit": false, "autostart": true, "ramdisk_scope": "container", "ramdisk": false, "prespawn": false, "is_default": false, "container_image_id": "507f1f77bcf86cd799439022", "environment_vars": {}, "volumes": {}, "ssh_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0wmN/CrjJXa/V2gV3L1q8TzX0Y2d5L3p7b6gK4yW1M user@host", "comment": null, "copy_firewall_rules": true, "copy_network_rules": false, "created_at": "2026-01-15T10:30:00.000Z", "updated_at": "2026-01-15T10:30:00.000Z", "realm_ids": [] }}{ "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. |
PROJECT_CONTAINER_LIMIT | Project container limit reached | The target project is at its owner-configured container quota (projects.max_containers). Prespawn containers are excluded from this quota. | Delete an existing container in this project, raise the project quota, or use a different project. |
{ "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 <token> |
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 |
{ "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 |
{ "statusCode": 404, "error": "Not Found", "message": "Source container not found"}| Error Code | Title | Description | Resolution |
|---|---|---|---|
SOURCE_CONTAINER_NOT_FOUND | Source container not found | The source container specified for a copy or sync operation does not exist. | Verify the source container ID is correct. |
RESOURCE_NOT_FOUND | Resource not found | The requested resource does not exist or has been deleted | Verify the resource ID and ensure it exists |
{ "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. |
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. |
Sync a copied container
Section titled “Sync a copied container”POST /api/v1/containers/{id}/sync
Section titled “POST /api/v1/containers/{id}/sync”Performs an incremental sync from the source container to this container. The sync only works for containers that were created via the copy operation (that is, containers that have a source_container_id). The operation runs asynchronously.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Unique identifier of the container to sync (must have been created via copy) |
curl -X POST https://api.hoody.icu/api/v1/containers/507f1f77bcf86cd799439099/sync \ -H "Authorization: Bearer <token>"await client.api.containers.sync("507f1f77bcf86cd799439099");{ "statusCode": 200, "message": "Container sync initiated successfully", "data": { "container_id": "507f1f77bcf86cd799439099", "source_container_id": "507f1f77bcf86cd799439011", "status": "copying" }}{ "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) |
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. |
{ "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 <token> |
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 |
{ "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 |
{ "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. |
{ "statusCode": 409, "error": "Conflict", "message": "Container was not created from a copy, sync is not possible."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
CONTAINER_NOT_COPIED | Container Not a Copy | The sync operation can only be performed on a container that was created by copying another. | This operation is only valid for containers with a source_container_id. |
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. |