Container Copy & Sync
Section titled “Container Copy & Sync”Copy a container from one project or server to another, and re-sync an existing copy with its source. Both operations run asynchronously — the new or updated container starts automatically once the operation completes.
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 in a different project or server. The copy operation runs asynchronously and the new container will start automatically upon successful completion.
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) |
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 chars, 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 |
kvm | boolean | No | — | Grant /dev/kvm passthrough (run full VMs) on the target server. Rented/dedicated targets only |
dev_kvm | boolean | No | — | Accepted alias of kvm on input. If both are sent, kvm wins and they must agree |
Example Request
Section titled “Example Request”curl -X POST https://api.hoody.com/api/v1/containers/{id}/copy \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "target_project_id": "67e89abc123def456789abcd", "target_server_id": "890abcdef12345678901cdef", "name": "prod-east-mirror", "copy_firewall_rules": true, "copy_network_rules": false }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.containers.copy('{id}', { target_project_id: '67e89abc123def456789abcd', target_server_id: '890abcdef12345678901cdef', name: 'prod-east-mirror', copy_firewall_rules: true, copy_network_rules: false});Response
Section titled “Response”{ "statusCode": 201, "message": "Container copy initiated successfully", "data": { "id": "890abcdef12345678901cdef", "name": "prod-east-mirror", "status": "copying", "source_container_id": "67e89abc123def456789abcd", "project_id": "67e89abc123def456789abcd", "project_alias": "production", "server_id": "890abcdef12345678901cdef", "server_name": "node-us", "subserver_name": "main", "server": { "name": "node-us", "country": "US", "country_name": "United States", "city": "Ashburn", "region": "North America", "datacenter": "IAD-DC1", "is_free": false, "specs": { "cpu_cores": 16, "ram_gb": 64, "disk_gb": 500, "shared_compute": false }, "expires_at": "2026-12-31T00:00:00.000Z" }, "ssh_hostname": "67e89abc123def456789abcd-890abcdef12345678901cdef-ssh.node-us.containers.hoody.com", "color": "#3B82F6", "container_image": "ubuntu-22.04", "ai": true, "hoody_kit": true, "dev_kit": false, "kvm": false, "autostart": true, "ramdisk_scope": "container", "ramdisk": false, "prespawn": false, "is_default": false, "container_image_id": "67e89abc123def456789ab01", "environment_vars": { "NODE_ENV": "production" }, "volumes": { "data": "/var/lib/data" }, "ssh_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... prod-east-mirror", "comment": "Mirrored copy of prod-east", "kvm_note": "", "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. Only works for containers that were created via the copy operation. The sync runs asynchronously.
This endpoint accepts no request body.
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) |
Example Request
Section titled “Example Request”curl -X POST https://api.hoody.com/api/v1/containers/{id}/sync \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
await client.api.containers.sync('{id}');Response
Section titled “Response”{ "statusCode": 200, "message": "Container sync initiated successfully", "data": { "container_id": "890abcdef12345678901cdef", "source_container_id": "67e89abc123def456789abcd", "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. |