Hoody API
Section titled “Hoody API”The Hoody API is the control plane. You use it to create projects and containers, configure their networking and proxy settings, and manage your account.
The Vision covers why Hoody is built this way. This page covers how the API is organized and what each group of endpoints does.
API endpoints summary
Section titled “API endpoints summary”This Foundation page explains how the Hoody API works. The reference pages below carry the complete endpoint documentation, with parameters and responses.
Core management:
- Authentication - Login, tokens, user sessions
- Auth Tokens - Long-lived automation credentials
- Users - Profile management
- Projects - Project CRUD operations
- Containers - Container lifecycle management
Networking and security:
- Realms - API-level isolation
- Container Network - Proxy/VPN routing
- Container Firewall - Ingress/egress rules
Proxy and routing:
- Proxy Aliases - Custom domain configuration
- Proxy Permissions - Access control
Data and state:
- Container Snapshots - State management
- Container Copy & Sync - Duplication
- Storage Shares - Shared directories
- Container Images - OS images
Two separate HTTP systems
Section titled “Two separate HTTP systems”Hoody exposes two HTTP surfaces, and they do different jobs:
Hoody API (Platform Management)
https://api.hoody.comWhat it controls:
- User authentication
- Project creation
- Container spawning
- Network configuration
- Firewall rules
- Proxy aliases
- Snapshots
- Billing
Mental model: “The dashboard API”
Container Services (Hoody Kit)
https://{project}-{container}-terminal-1.node-sg-sin-1.containers.hoody.comhttps://{project}-{container}-display-1.node-sg-sin-1.containers.hoody.comhttps://{project}-{container}-files-1.node-sg-sin-1.containers.hoody.comWhat they provide:
- Terminal execution
- Desktop access
- File operations
- Database queries
- Browser automation
- Script execution
- +12 more services
Mental model: “The containers themselves”
The two are used in sequence:
- Use the Hoody API to spawn a container
- The container gets URLs for all its services automatically
- Use those URLs to work with the container
The Hoody API creates the infrastructure. The container URLs are how you use it.
What the Hoody API does
Section titled “What the Hoody API does”The endpoints fall into seven areas.
Authentication and users
Section titled “Authentication and users”Manage your account and create access credentials:
# Login as a userhoody auth login --username your_username --password your_password
# Create long-lived API token for automationhoody auth create --alias "my-automation-token" --expires-at "2027-04-12T00:00:00Z"
# Get current user profilehoody auth profile currentimport { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });
// Get current user profileconst me = await client.api.authentication.getCurrentUser();console.log(me.data);
// Create long-lived API tokenconst token = await client.api.authTokens.create({ alias: 'my-automation-token', expires_at: '2027-04-12T00:00:00Z'});# Login as a usercurl -X POST "https://api.hoody.com/api/v1/users/auth/login" \ -H "Content-Type: application/json" \ -d '{"username": "your_username", "password": "your_password"}'
# Create long-lived API token for automationcurl -X POST "https://api.hoody.com/api/v1/auth/tokens" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"alias": "my-automation-token", "expires_at": "2027-04-12T00:00:00Z"}'
# Get current user profilecurl "https://api.hoody.com/api/v1/users/auth/me" \ -H "Authorization: Bearer $TOKEN"One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Log in, create a long-lived auth token for automation, and fetch the current user profile. The last two calls use an existing token as bearer auth.
# Login
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/users/auth/login&method=POST&json={"username":"your_username","password":"your_password"}&response=transparent
# Create token
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/auth/tokens&method=POST&bearer_token=TOKEN&json={"alias":"my-automation-token","expires_at":"2027-04-12T00:00:00Z"}&response=transparent
# Get profile
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/users/auth/me&method=GET&bearer_token=TOKEN&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
See: Authentication → | API Reference →
Projects
Section titled “Projects”Projects are the folders that hold your containers:
# Create a projecthoody projects create --alias "my-project"
# List your projectshoody projects list// Create a projectconst project = await client.api.projects.create({ alias: 'my-project' });
// List your projectsconst projects = await client.api.projects.list();# Create a projectcurl -X POST "https://api.hoody.com/api/v1/projects/" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"alias": "my-project"}'
# List your projectscurl "https://api.hoody.com/api/v1/projects/" \ -H "Authorization: Bearer $TOKEN"One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Create and list share one collection URL. The POST carries the new project’s alias as its body; the GET takes no body and returns every project you own.
# Create a project
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/projects/&method=POST&bearer_token=TOKEN&json={"alias":"my-project"}&response=transparent
# List your projects
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/projects/&method=GET&bearer_token=TOKEN&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
See: Projects & Containers → | API Reference →
Containers
Section titled “Containers”Create an isolated container inside a project:
# Spawn a container in a projecthoody containers create --project $PROJECT_ID --server-id $SERVER_ID --name "dev-env"
# Container URLs are automatically constructed:# https://{project_id}-{container_id}-terminal-1.{server_name}.containers.hoody.com# https://{project_id}-{container_id}-display-1.{server_name}.containers.hoody.com# ... plus files, exec, agent, sqlite, curl, cron, pipe, n, browser, code, daemon, notes, watch, run, logs, tunnel, and dynamic http/https ports// Spawn a container in a projectconst container = await client.api.containers.create( projectId, { name: 'dev-env', server_id: serverId, hoody_kit: true, dev_kit: true });
// Container URLs are automatically availableconsole.log(container.data);# Spawn a container in a projectcurl -X POST "https://api.hoody.com/api/v1/projects/$PROJECT_ID/containers" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "dev-env", "server_id": "'$SERVER_ID'", "hoody_kit": true, "dev_kit": true}'
# Response includes container_id and server details# Container URLs are automatically constructed:# https://{project_id}-{container_id}-terminal-1.{server_name}.containers.hoody.com# https://{project_id}-{container_id}-display-1.{server_name}.containers.hoody.com# ... plus files, exec, agent, sqlite, curl, cron, pipe, n, browser, code, daemon, notes, watch, run, logs, tunnel, and dynamic http/https portsOne request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Spawn a container in a project with Hoody Kit and Dev Kit enabled.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/projects/PROJECT_ID/containers&method=POST&bearer_token=TOKEN&json={"name":"dev-env","server_id":"SERVER_ID","hoody_kit":true,"dev_kit":true}&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
The container is running with all its HTTP services live within 1-5 seconds.
See: Container Lifecycle → | API Reference →
Networking and security
Section titled “Networking and security”Configure how containers connect and communicate:
# Configure firewall rulesPOST https://api.hoody.com/api/v1/containers/{id}/firewall/ingress
# Route traffic through proxies/VPNsPATCH https://api.hoody.com/api/v1/containers/{id}/network
# Add an outbound firewall rulePOST https://api.hoody.com/api/v1/containers/{id}/firewall/egressSee: Networking → | Firewall →
Proxy configuration
Section titled “Proxy configuration”Give a container a shorter, custom URL and control who can reach it:
# Create custom alias: my-app.$serverName.containers.hoody.comPOST https://api.hoody.com/api/v1/proxy/aliases
# Configure permissionsPATCH https://api.hoody.com/api/v1/containers/{id}/proxy/permissionsSee: Hoody Proxy → | Aliases →
Storage and snapshots
Section titled “Storage and snapshots”Manage persistent data and state:
# Snapshot a container (capture complete state)POST https://api.hoody.com/api/v1/containers/{id}/snapshots
# Share directories between containersPOST https://api.hoody.com/api/v1/containers/{id}/storage/sharesSee: Snapshots → | Storage Shares →
Infrastructure management
Section titled “Infrastructure management”Inspect the servers and images behind your containers:
# List your active server rentalsGET https://api.hoody.com/api/v1/rentals
# Manage container imagesGET https://api.hoody.com/api/v1/images/publicHTTP-first design
Section titled “HTTP-first design”The Hoody API is plain REST over HTTP, which has two practical consequences.
Access from AI agents
Section titled “Access from AI agents”LLMs are trained on HTTP, so they already know how to construct JSON payloads, make authenticated requests, parse responses, and handle errors.
There is no SDK to install. An agent can drive your whole infrastructure over HTTP:
// An agent can write this from the endpoint list aloneconst workflow = [ { description: "Create project for client", call: "POST https://api.hoody.com/api/v1/projects/", body: { alias: "client-acme", color: "#3498db" } }, { description: "Spawn 3 containers: frontend, backend, database", call: "POST https://api.hoody.com/api/v1/projects/{project_id}/containers", repeat: 3, body: { server_id: "...", hoody_kit: true, dev_kit: true } }, { description: "Configure firewall for database", call: "POST https://api.hoody.com/api/v1/containers/{db_id}/firewall/ingress", body: { action: "allow", protocol: "tcp", description: "Allow backend to database", destination_port: "5432", source: "{backend_ip}" } }];
// Each step runs over plain HTTP, without a custom SDKfor (const step of workflow) { const [method, url] = step.call.split(' '); const response = await fetch(url, { method, headers: { 'Authorization': `Bearer ${process.env.HOODY_TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify(step.body) });}Access from any language
Section titled “Access from any language”Every programming language has HTTP libraries:
# List all projectshoody projects listimport { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });const projects = await client.api.projects.list();console.log(projects.data);curl "https://api.hoody.com/api/v1/projects/" \ -H "Authorization: Bearer $HOODY_TOKEN"One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
List your projects using the API token from your environment.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/projects/&method=GET&bearer_token=HOODY_TOKEN&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
The SDK is optional. Any language with an HTTP client can call the API directly, including JavaScript, Python, Go, and Ruby.
The full workflow
Section titled “The full workflow”1. AUTHENTICATE POST /api/v1/users/auth/login → Receive JWT tokens
2. CREATE AUTH TOKEN (for automation) POST /api/v1/auth/tokens → Get hdy_... token with IP whitelist, expiration → Use this in scripts/AI instead of user credentials
3. CREATE PROJECT POST /api/v1/projects/ → Get project_id
4. SPAWN CONTAINER POST /api/v1/projects/{project_id}/containers → Get container_id, server_name → Container URLs automatically available: • https://{project_id}-{container_id}-terminal-1.{server_name}.containers.hoody.com • https://{project_id}-{container_id}-display-1.{server_name}.containers.hoody.com • https://{project_id}-{container_id}-exec-1.{server_name}.containers.hoody.com • ... plus files, agent, sqlite, curl, cron, pipe, n, browser, code, daemon, notes, watch, run, logs, tunnel, and dynamic http/https ports
5. CONFIGURE (optional) PATCH /api/v1/containers/{id}/network → Route through VPN POST /api/v1/containers/{id}/firewall/ingress → Add inbound firewall rule POST /api/v1/containers/{id}/firewall/egress → Add outbound firewall rule POST /api/v1/proxy/aliases → Create custom domain
6. USE CONTAINER SERVICES # Now use the container URLs directly POST https://{project}-{container}-terminal-1.{server}.containers.hoody.com/api/v1/terminal/execute GET https://{project}-{container}-files-1.{server_name}.containers.hoody.com/api/v1/files/home/API organization
Section titled “API organization”The endpoint reference is grouped by area:
Core management
Section titled “Core management”- Authentication - Login, tokens, sessions
- Auth Tokens - Long-lived automation credentials
- Users - Profile management
- Projects - Project CRUD operations
- Containers - Container lifecycle
Networking and access
Section titled “Networking and access”- Realms - API-level isolation (scope operations to specific realms via
{realmId}.api.hoody.com) - Container Network - Proxy/VPN routing
- Container Firewall - Ingress/egress rules
- IPv4 - Dedicated IP addresses
Proxy and routing
Section titled “Proxy and routing”- Proxy Aliases - Custom domains (my-app.$serverName.containers.hoody.com)
- Proxy Permissions (Project) - Project-level access control
- Proxy Permissions (Container) - Container-level overrides
Data and state
Section titled “Data and state”- Container Snapshots - Point-in-time filesystem snapshots
- Container Copy & Sync - Duplicate and sync containers
- Storage Shares - Share directories between containers
- Container Images - OS images and marketplace
Infrastructure
Section titled “Infrastructure”- Notifications - Platform announcements
- Wallet - Billing and credits
Standard patterns
Section titled “Standard patterns”Authentication
Section titled “Authentication”Almost every request requires authentication. Login and a few public endpoints, such as GET /api/v1/notifications/public, are the exceptions.
# Login (stores credentials locally)hoody auth login --username your_username --password your_password
# All subsequent commands use the stored tokenhoody projects listhoody containers listimport { HoodyClient } from 'hoody-sdk';
// Option 1: Auth Token (recommended for automation)const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN // hdy_... token});
// All API calls are authenticated automaticallyconst projects = await client.api.projects.list();# Option 1: User JWT (from login)curl "https://api.hoody.com/api/v1/projects/" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# Option 2: Auth Token (recommended for automation)curl "https://api.hoody.com/api/v1/projects/" \ -H "Authorization: Bearer hdy_abc123def456..."One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
List your projects authenticated either way: with the short-lived JWT from login, or with a long-lived Auth Token.
# User JWT
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/projects/&method=GET&bearer_token=JWT&response=transparent
# Auth Token
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/projects/&method=GET&bearer_token=HOODY_TOKEN&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
For automation and AI, use Auth Tokens: long-lived, IP-restricted, and revocable. For user sessions, use the JWT from login, which is short-lived and refreshable.
Error handling
Section titled “Error handling”The standard error response:
{ "statusCode": 400, "error": "Bad Request", "message": "Detailed explanation of what went wrong"}Common status codes:
400- Bad Request (validation errors)401- Unauthorized (missing/invalid token)403- Forbidden (insufficient permissions)404- Not Found (resource doesn’t exist)409- Conflict (duplicate name, invalid state)500- Internal Server Error
Pagination
Section titled “Pagination”List endpoints support pagination:
GET /api/v1/projects/?page=1&limit=20&sort_by=created_at&sort_order=descThe response includes pagination metadata:
{ "data": { "projects": [...], "pagination": { "total": 150, "page": 1, "limit": 20, "totalPages": 8 } }}Filtering and sorting
Section titled “Filtering and sorting”Many endpoints support filtering:
# Filter containers by realmGET /api/v1/containers/?realm_id=507f1f77bcf86cd799439011
# Sort by statusGET /api/v1/containers/?sort_by=status&sort_order=desc
# Sort by creation dateGET /api/v1/projects/?sort_by=created_at&sort_order=descHTTP instead of CLI tools and SDKs
Section titled “HTTP instead of CLI tools and SDKs”Most platforms manage infrastructure through one of three surfaces:
- CLI tools (installed binaries, version conflicts)
- Custom SDKs (language-specific, maintenance burden)
- Proprietary protocols (hard to debug)
Hoody uses HTTP, so the control plane is:
- Callable from any language and any device
- Understood natively by AI agents
- Reachable with curl, from a script, or from a browser
- Observable, debuggable, and auditable
- Composable with any other HTTP service
The same provisioning flow from an AI agent, using only fetch:
// Provision a client project: containers, alias, firewall ruleasync function deployClientProject(clientName) { const token = process.env.HOODY_TOKEN; const headers = { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' };
// 1. Create project const project = await fetch('https://api.hoody.com/api/v1/projects/', { method: 'POST', headers, body: JSON.stringify({ alias: `client-${clientName}`, color: '#3498db', max_containers: 50 }) }).then(r => r.json());
// 2. Spawn 3 containers (frontend, backend, database) const containers = await Promise.all([ 'frontend', 'backend', 'database' ].map(name => fetch(`https://api.hoody.com/api/v1/projects/${project.data.id}/containers`, { method: 'POST', headers, body: JSON.stringify({ name, server_id: 'your-server-id', hoody_kit: true, dev_kit: true }) }).then(r => r.json()) ));
// 3. Create production alias await fetch('https://api.hoody.com/api/v1/proxy/aliases', { method: 'POST', headers, body: JSON.stringify({ container_id: containers[0].data.id, alias: `${clientName}-app`, program: 'http', port: 80 }) });
// 4. Configure firewall for database await fetch(`https://api.hoody.com/api/v1/containers/${containers[2].data.id}/firewall/ingress`, { method: 'POST', headers, body: JSON.stringify({ action: 'allow', protocol: 'tcp', destination_port: '5432', source: '10.0.1.30/32', // backend container's private IP/CIDR description: 'Allow backend to database' }) });
return { projectId: project.data.id, containers: containers.map(c => ({ name: c.data.name, terminalUrl: `https://${project.data.id}-${c.data.id}-terminal-1.${c.data.server_name}.containers.hoody.com`, displayUrl: `https://${project.data.id}-${c.data.id}-display-1.${c.data.server_name}.containers.hoody.com` })) };}API base URLs
Section titled “API base URLs”Global API:
https://api.hoody.comRealm-scoped API (for multi-tenant isolation):
https://{realmId}.api.hoody.comWhen you use a realm-scoped URL:
- The subdomain realm must be a 24-char hex ID
- Read operations are scoped to resources in that realm
- Create/update operations preserve or merge that realm where supported
- Container
realm_idsare set independently of the parent project’srealm_ids - API tokens can be restricted to specific realms
- Realm-restricted tokens can bootstrap via
GET /api/v1/auth/tokens/meon base host
Realm scoping is how a multi-tenant SaaS keeps each tenant’s API calls separated.
See: Realms → for realm-based API isolation.
Response format
Section titled “Response format”All responses follow this structure:
{ "statusCode": 200, "message": "Human-readable success message", "data": { // The actual response data }}Errors include details:
{ "statusCode": 400, "error": "Bad Request", "message": "Container name must be unique within project"}Getting started
Section titled “Getting started”Your first API calls:
Gives you: JWT access token
Gives you: hdy_... token for scripts/AI
Gives you: Project ID
Gives you: Container with 18 live HTTP service URLs
Four API calls give you a running container with terminal, display, files, database, and 14 more HTTP services.
Useful questions
Section titled “Useful questions”What’s the difference between the API and container URLs?
Section titled “What’s the difference between the API and container URLs?”The Hoody API (api.hoody.com) manages your infrastructure: creating containers, configuring networks, and billing. Container service URLs ({project}-{container}-terminal-1.{server}.containers.hoody.com) are the containers themselves, where you execute commands, access files, and run applications.
Think of it like AWS: the AWS Console (Hoody API) vs. your EC2 instance (container URLs).
Can I use the Hoody API without the Hoody Kit?
Section titled “Can I use the Hoody API without the Hoody Kit?”Yes. Set hoody_kit: false when creating a container to get a plain Linux container without the 18 HTTP services. You still use the Hoody API to manage it, but the container has no terminal, files, or display HTTP endpoints: only SSH and whatever you install yourself.
Do I need different auth tokens for different projects?
Section titled “Do I need different auth tokens for different projects?”Not required, but recommended for blast-radius control. One token can cover multiple projects, while per-app/per-realm tokens are easier to audit and revoke.
How quickly can I spawn a container via the API?
Section titled “How quickly can I spawn a container via the API?”Typically 1-5 seconds from API call to a running container with all services live. Prespawn Templates cut this to sub-second by keeping pools of pre-created containers.
Can AI agents directly use the Hoody API?
Section titled “Can AI agents directly use the Hoody API?”Yes. An agent needs only a Hoody auth token, usually from an environment variable, and can then drive your whole infrastructure with standard HTTP requests. LLMs are trained on web data, so HTTP itself needs no explanation, and no SDK is required.
What happens if I delete a project via the API?
Section titled “What happens if I delete a project via the API?”All containers in that project are immediately terminated and deleted. The deletion is permanent and cannot be undone, so snapshot anything you need before deleting a project. The CLI and MCP surfaces gate this with an interactive confirmation prompt; a direct HTTP call proceeds with no extra confirm parameter, so handle the prompt in your own tooling.
Can I automate infrastructure with GitHub Actions?
Section titled “Can I automate infrastructure with GitHub Actions?”Yes. Store your Hoody auth token as a GitHub Secret (HOODY_TOKEN), then call the API with curl or any HTTP library from your workflow. A common pattern is deploying on push by creating or updating containers through the API.
Is there a rate limit on the Hoody API?
Section titled “Is there a rate limit on the Hoody API?”The current limits are set for automation: you can spawn dozens of containers per minute. When you exceed one, the API returns 429 Too Many Requests with retry timing. Contact support if you need higher limits for enterprise-scale automation.
Can I scope operations to specific realms?
Section titled “Can I scope operations to specific realms?”Yes. Use realm-scoped API URLs: https://{realmId}.api.hoody.com instead of https://api.hoody.com.
Key rules:
{realmId}must be a 24-hex realm ID.- Realm-restricted tokens (
realm_idsnon-empty orallow_no_realm: false) must use realm-scoped URLs for resource operations. GET /api/v1/auth/tokens/meis the bootstrap endpoint for discovering allowed realms.
What’s the maximum number of containers I can create?
Section titled “What’s the maximum number of containers I can create?”There’s no account-wide cap, but two limits are enforced at every creation. First, a per-server cap: free-pool servers default to 10 containers each (FREE_SERVER_MAX_CONTAINERS), and any server can carry an explicit max_containers. Second, a per-project quota: the project’s max_containers field (null = unlimited). Exceeding either fails the create with 400. Beyond those, the practical limits are server resources (CPU/RAM) and organization (managing hundreds of containers becomes complex). Use projects to organize, and consider prespawn templates for container pooling at scale.
Troubleshooting
Section titled “Troubleshooting”401 Unauthorized
Section titled “401 Unauthorized”Problem: All API requests return 401 Unauthorized
Solutions:
-
Check token is included:
Terminal window # Ensure Authorization header is presentcurl -v "https://api.hoody.com/api/v1/projects/" \-H "Authorization: Bearer $HOODY_TOKEN"# Look for: > Authorization: Bearer hdy_... -
Verify token format:
Terminal window # JWT tokens start with: eyJ...# Auth tokens start with: hdy_...echo $HOODY_TOKEN -
Check token expiration:
- Re-authenticate:
403 Forbidden (Auth Token IP whitelist)
Section titled “403 Forbidden (Auth Token IP whitelist)”Problem: Auth Token returns 403 Forbidden
Cause: Your current IP is not in the token’s IP whitelist
Check your IP:
Compare ip_whitelist with your current IP (run curl https://ifconfig.me in terminal).
Solutions:
- Update whitelist to include your IP:
- Create new token without IP restrictions:
404 Not Found
Section titled “404 Not Found”Problem: Resource not found errors
Common causes:
-
Wrong ID format:
Terminal window # IDs must be 24-character hex# Wrong: abc123# Correct: 507f1f77bcf86cd799439011 -
Resource doesn’t exist:
Terminal window # Verify resource existsGET /api/v1/projects/ # List all projectsGET /api/v1/containers/ # List all containers -
Wrong endpoint path:
/api/v1/project/507f1f77bcf86cd799439011 # Correct: /api/v1/projects/507f1f77bcf86cd799439011
Network and connection errors
Section titled “Network and connection errors”Problem: Can’t reach api.hoody.com
Solutions:
-
Check internet connection:
Terminal window ping api.hoody.com -
Verify DNS resolution:
Terminal window dig api.hoody.com# Should return IP address -
Test with curl verbose:
Terminal window curl -v "https://api.hoody.com/api/v1/projects/" \-H "Authorization: Bearer $HOODY_TOKEN"# Look for TLS handshake and connection details -
Check firewall/proxy:
- Corporate firewall might block HTTPS
- VPN might interfere with connections
- Try from different network
Rate limiting
Section titled “Rate limiting”Problem: 429 Too Many Requests
Solution: the Hoody API rate limits are set for automation. If you hit one:
-
Add delays between requests:
for (const item of items) {await fetch(apiUrl, options);await new Promise(r => setTimeout(r, 100)); // 100ms delay} -
Batch operations where possible:
Terminal window # Instead of 10 separate container creates# Create them with delay or use prespawn pools
Getting help
Section titled “Getting help”If the problem persists:
- Review error message - Hoody returns detailed error messages in JSON
- Contact support with:
- Request method and endpoint
- Request headers (mask auth token)
- Error response
- Timestamp of failure
Next steps
Section titled “Next steps”Understand the foundation:
- Authentication → - How to authenticate (JWTs vs Auth Tokens)
- Projects & Containers → - How Hoody groups containers into projects
- Hoody Proxy → - How every container feature becomes a URL
See the complete endpoint documentation:
- API Reference → - Every endpoint with its parameters and responses