API Overview

The Circloud API allows you to programmatically manage your VPCs, subnets, pods, and tunnels.

Base URL: https://api.circloud.net (public) or https://localhost:8080 (local)
Authentication: Tenant endpoints use X-Auth-Token; admin endpoints use X-Admin-Token.

Authentication

Include your tenant API token in every request:

curl -k -X GET https://api.circloud.net/vpcs \
  -H "X-Auth-Token: YOUR_API_TOKEN"

Admin endpoints require an admin token:

curl -k -X GET https://api.circloud.net/tenants \
  -H "X-Admin-Token: YOUR_ADMIN_TOKEN"

Many create endpoints also accept a token field in the JSON body. The header is still required and is the primary authentication check.

POST /admin/login Admin login

Request Body

ParameterTypeRequiredDefaultDescription
username*stringYes-Admin username
password*stringYes-Admin password

Response

200 Admin user with api_token

Tenant Endpoints (Admin)

Manage tenant lifecycle and retrieve full tenant topology. Requires X-Admin-Token.

POST /tenants Create tenant

Request Body

ParameterTypeRequiredDefaultDescription
name*stringYes-Tenant name (DNS-compliant)
descriptionstringNonullOptional description
password*stringYes-Login password for tenant GUI
GET /tenants List tenants

Response

200 Array of tenants

GET /tenants/{tenant_id} Get tenant with topology and status

Response

200 Tenant object with VPCs, pods, tunnels, and pod status

DELETE /tenants/{tenant_id} Delete tenant

Response

204 Tenant deleted (cascades to all resources)

Domain Endpoints (Admin)

Assign custom domains to tenants for tunnel usage.

POST /tenants/{tenant_id}/domains Add custom domain

Request Body

ParameterTypeRequiredDefaultDescription
domain*stringYes-Domain name (e.g., example.com)
GET /tenants/{tenant_id}/domains List tenant domains

Response

200 Array of domains

Provider Config (Admin)

Configure external subnet, DNS, and Cloudflare credentials.

POST /provider-config Create or update provider config

Request Body

ParameterTypeRequiredDefaultDescription
external_subnet_cidr*stringYes-External subnet CIDR
external_subnet_gateway*stringYes-Gateway for external subnet
peering_subnet_cidr*stringYes-Peering subnet for core services
pod_dns_nameserversarrayNo[]External DNS resolvers
pod_dns_ndotsintegerNonullDNS ndots setting
cloudflare_account_idstringNonullCloudflare account ID
cloudflare_api_tokenstringNonullCloudflare API token
cloudflare_domainstringNonullDefault tunnel domain
GET /provider-config Get provider config

Response

200 Provider configuration

VPC Endpoints

Create and manage Virtual Private Clouds.

POST /vpcs Create a VPC

Request Body

ParameterTypeRequiredDefaultDescription
tenant_id*stringYes-Your tenant UUID
token*stringYes-Your API token
name*stringYes-VPC name (DNS-compliant)
enable_internet*booleanYes-Enable internet access

Example

curl -k -X POST https://api.circloud.net/vpcs \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "YOUR_TENANT_ID",
    "token": "YOUR_TOKEN",
    "name": "production",
    "enable_internet": true
  }'
GET /vpcs List all VPCs

Response

200 Array of VPCs

DELETE /vpcs/{vpc_id} Delete a VPC

Response

204 VPC deleted (cascades to subnets and pods)

Subnet Endpoints

Create and manage subnets within VPCs.

POST /subnets Create a subnet

Request Body

ParameterTypeRequiredDefaultDescription
tenant_id*stringYes-Your tenant UUID
token*stringYes-Your API token
vpc_id*stringYes-Parent VPC UUID
name*stringYes-Subnet name
cidr*stringYes-CIDR block (e.g., "10.100.1.0/24")
gateway_ip*stringYes-Gateway IP within CIDR

Example

curl -k -X POST https://api.circloud.net/subnets \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "YOUR_TENANT_ID",
    "token": "YOUR_TOKEN",
    "vpc_id": "VPC_ID",
    "name": "web-tier",
    "cidr": "10.100.1.0/24",
    "gateway_ip": "10.100.1.1"
  }'
GET /subnets List all subnets

Response

200 Array of subnets

Pod Endpoints

Deploy and manage containerized workloads.

POST /pods Create a pod

Request Body

ParameterTypeRequiredDefaultDescription
tenant_id*stringYes-Your tenant UUID
token*stringYes-Your API token
vpc_id*stringYes-Target VPC UUID
subnet_id*stringYes-Target subnet UUID
name*stringYes-Pod name (DNS-compliant)
container_image*stringYes-Container image (e.g., "nginx:latest")
replica_countintegerNo1Replica count (1-10). If auto_scaling is true, this is the initial replica count (min 2)
service_portintegerNo80VIP service port (default 80)
use_registry_credentialsbooleanNotrueUse tenant registry secret for image pulls
external_accessbooleanNofalseEnable outbound internet (SNAT)
external_inboundbooleanNofalseEnable inbound with external IP (requires external_access)
auto_healingbooleanNofalseAuto-restart on failure
auto_scalingbooleanNofalseEnable autoscaling with HPA (CPU-based)
autoscale_max_replicasintegerNo10Maximum replicas when autoscaling (default 10)
autoscale_cpu_target_millicoresintegerNo200Target average CPU usage per pod in millicores (default 200)
tunnelsarrayNo[]Inline tunnel definitions for this pod

Notes: For replicas, Circloud creates one VIP service that load-balances across all replicas. Auto-scaling creates an HPA (auto_healing is implied), and the minimum replica count is always 2. Live status data is available in the admin /tenants/{tenant_id} response.

Example

curl -k -X POST https://api.circloud.net/pods \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "YOUR_TENANT_ID",
    "token": "YOUR_TOKEN",
    "vpc_id": "VPC_ID",
    "subnet_id": "SUBNET_ID",
    "name": "web-server",
    "container_image": "nginx:latest",
    "replica_count": 2,
    "service_port": 80,
    "external_access": true,
    "external_inbound": true,
    "auto_scaling": true,
    "autoscale_max_replicas": 6,
    "autoscale_cpu_target_millicores": 250
  }'
POST /pods/{pod_id}/replicas Add one replica

Response

200 Pod object with updated replica_count

Note: Adds a single replica and updates the logical pod's replica_count. Not available when auto_scaling is enabled.

DELETE /pods/{pod_id}/replicas Remove one replica

Response

200 Pod object with updated replica_count

Note: Removes a single replica (minimum 1). Not available when auto_scaling is enabled.

POST /pods/{pod_id}/restart Restart a pod

Response

200 Pod restart initiated

GET /pods List all pods

Response

200 Array of pods with status

DELETE /pods/{pod_id} Delete a pod

Response

204 Pod deleted

PATCH /pods/{pod_id}/config Update pod configuration

Update pod runtime configuration (auto-healing, persistent storage, autoscaling). Stops the workload, applies changes, and recreates with new settings. Network resources (VIP, DNS, EIP) are preserved.

Request Body (all fields optional)

ParameterTypeRequiredDefaultDescription
auto_healingbooleanNo-Toggle auto-healing (Deployment-backed)
persistentbooleanNo-Toggle persistent host-path storage
persistent_mount_pathstringNo/storageMount path for persistent storage
auto_scalingbooleanNo-Toggle CPU-based autoscaling (HPA)
autoscale_min_replicasintegerNo2Minimum replicas for autoscaling (2-50)
autoscale_max_replicasintegerNo10Maximum replicas for autoscaling (2-50)
autoscale_cpu_target_millicoresintegerNo200Target CPU per pod in millicores (10-10000)

Edge cases: Enabling auto_scaling forces auto_healing on. Disabling auto_healing also disables auto_scaling. GPU access cannot be changed after creation.

Example — Enable autoscaling

curl -k -X PATCH https://api.circloud.net/pods/POD_ID/config \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "auto_scaling": true,
    "autoscale_max_replicas": 6,
    "autoscale_cpu_target_millicores": 250
  }'

Example — Enable persistent storage

curl -k -X PATCH https://api.circloud.net/pods/POD_ID/config \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "persistent": true,
    "persistent_mount_path": "/data"
  }'

Response

200 Updated pod object

409 Pod is stopped or being deleted

Tunnel Endpoints

Create Cloudflare tunnels for secure external access via Cloudflare's global network.

Supported Protocols

ProtocolUse CasesHow to Connect
httpWeb apps, REST APIs, webhooksBrowser: https://subdomain.domain.com
httpsEnd-to-end encryption, mTLSBrowser: https://subdomain.domain.com
sshRemote terminal, SFTP, Gitcloudflared access ssh --hostname host
tcpDatabases (PostgreSQL, MySQL, Redis)cloudflared access tcp --hostname host
udpGame servers, VoIP, DNSDirect: hostname:port
POST /pods/{pod_id}/tunnel Create tunnel for pod

Request Body

ParameterTypeRequiredDefaultDescription
tunnel_name*stringYes-Unique tunnel name
subdomain*stringYes-Subdomain for access
protocol_type*stringYes-http, https, ssh, tcp, udp
service_portintegerNo80Target port (default: 80)
domainstringNonullCustom domain (must be approved)

HTTP Tunnel (Web Apps)

curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tunnel_name": "web-app",
    "subdomain": "app",
    "protocol_type": "http",
    "service_port": 80
  }'
# Access: https://app.yourdomain.com

SSH Tunnel (Remote Access)

curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tunnel_name": "ssh-access",
    "subdomain": "ssh",
    "protocol_type": "ssh",
    "service_port": 22
  }'
# Connect: cloudflared access ssh --hostname ssh.yourdomain.com

TCP Tunnel (Database)

curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tunnel_name": "database",
    "subdomain": "db",
    "protocol_type": "tcp",
    "service_port": 5432
  }'
# Connect: cloudflared access tcp --hostname db.yourdomain.com --url localhost:5432
# Then: psql -h localhost -p 5432 -U myuser mydb

UDP Tunnel (Game Server)

curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tunnel_name": "game-server",
    "subdomain": "game",
    "protocol_type": "udp",
    "service_port": 27015
  }'
# Connect directly: game.yourdomain.com:27015

Response

201 Tunnel created

{
  "id": "tunnel-uuid",
  "tunnel_name": "web-tunnel",
  "hostname": "app.yourdomain.com",
  "protocol_type": "http",
  "status": "active"
}
POST /tunnels?pod_id={pod_id} Create tunnel (auto-named)

Notes

Uses the pod ID query parameter and auto-derives the tunnel name from the pod.

GET /pods/{pod_id}/tunnels List tunnels for pod

Response

200 Array of tunnels for the pod

GET /tunnels List all tunnels

Response

200 Array of tunnels

DELETE /tunnels/{tunnel_id} Delete tunnel

Response

204 Tunnel deleted

Admin: POST /service-tunnels creates Cloudflare tunnels for platform services (API, GUIs) using X-Admin-Token.

Registry Credentials

Manage private container registry credentials.

POST /tenants/{tenant_id}/registry-credentials Add registry credentials

Request Body

ParameterTypeRequiredDefaultDescription
name*stringYes-Registry name (e.g., "dockerhub")
server*stringYes-Registry server URL
username*stringYes-Registry username
password*stringYes-Registry password/token

Example

curl -k -X POST https://api.circloud.net/tenants/YOUR_TENANT_ID/registry-credentials \
  -H "X-Auth-Token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "dockerhub",
    "server": "https://index.docker.io/v1/",
    "username": "myusername",
    "password": "mytoken"
  }'
GET /tenants/{tenant_id}/registry-credentials List registry credentials

Response

200 Array of credentials (passwords hidden)

DELETE /tenants/{tenant_id}/registry-credentials/{name} Delete registry credentials

Response

200 Credential deleted

Topology API

Deploy complete infrastructure in a single API call.

POST /tenants/{tenant_id}/topology Deploy topology

Request Body

ParameterTypeRequiredDefaultDescription
token*stringYes-Your API token
vpcs*arrayYes-Array of VPC definitions
subnets*arrayYes-Array of subnet definitions
podsarrayNo[]Array of pod definitions

Example

curl -k -X POST https://api.circloud.net/tenants/TENANT_ID/topology \
  -H "Content-Type: application/json" \
  -d '{
    "token": "YOUR_TOKEN",
    "vpcs": [
      {"name": "production", "enable_internet": true}
    ],
    "subnets": [
      {
        "name": "web",
        "vpc_name": "production",
        "cidr": "10.100.1.0/24",
        "gateway_ip": "10.100.1.1"
      }
    ],
    "pods": [
      {
        "name": "nginx",
        "vpc_name": "production",
        "subnet_name": "web",
        "container_image": "nginx:latest",
        "replica_count": 2,
        "service_port": 80,
        "auto_scaling": true,
        "autoscale_max_replicas": 6,
        "autoscale_cpu_target_millicores": 250
      }
    ]
  }'
GET /tenants/{tenant_id}/topology Get current topology

Response

200 Current topology as JSON

Health & Version

Check API health and version information.

curl -k https://api.circloud.net/healthz
curl -k https://api.circloud.net/version

Error Handling

All errors return a JSON response with a detail field.

Status CodeDescription
200Request succeeded
201Resource created
204Resource deleted
400Invalid parameters
401Invalid token
404Resource not found
409Resource conflict
{"detail": "Error message describing what went wrong"}

Support

Support the Circloud project with a donation.