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

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.