Deploy Lifecycle
Introduction
Buddo provides containerized application hosting for operators. You build a container image, push it to a supported registry, and the platform handles provisioning, networking, TLS, health monitoring, and billing. Your app runs on dedicated infrastructure (container-host-1) — isolated from the core Buddo API servers.
This guide walks through the complete deployment lifecycle: from registering your first app to monitoring, updating, and tearing down deployments. For full endpoint schemas and response details, see the Deploy API Reference.
deploy:manage scope.
All deploy endpoints require an OAuth access token with the
deploy:manage scope. See the
OAuth PKCE guide for how to obtain one.
Overview
The deployment pipeline from creation to live traffic follows this path:
Register OAuth app Choose a deploy tier Create deployment
(deploy:manage scope) GET /api/deploy/tiers POST /api/deploy/apps
| | |
v v v
Obtain access token ----> Select tier (buddo/btc) ----> Subdomain + image + tier
|
v
Platform provisions container
(Podman on container-host-1)
|
v
Caddy binds subdomain.buddocloud.com
(+ custom domain if configured)
|
v
TLS auto-provisioned via Caddy/ACME
|
v
Health checks begin · App is LIVE
|
_____________________|_____________________
| | | |
v v v v
Monitor Restart Update Destroy
GET .../status POST .../restart (redeploy) DELETE .../
Step 1: Choose a Deploy Tier
Before creating a deployment, query the available tiers to understand the resource limits and pricing for each option.
Endpoint
GET
/api/deploy/tiers
cURL Example
curl https://api.buddo.xyz/api/deploy/tiers \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN"
Response
Returns an array of DeployTier objects. Each tier includes:
| Field | Description |
|---|---|
name / slug | Human-readable name and the slug you pass to the create endpoint |
payment_method | buddo_points or bitcoin |
monthly_cost_points | Monthly cost in Buddo points (null for Bitcoin tiers) |
monthly_cost_sats | Monthly cost in satoshis (null for Buddo tiers) |
memory_limit_mb | Container memory cap in MB |
cpu_limit_millicores | CPU allocation in millicores |
custom_domain_allowed | Whether this tier permits binding a custom domain |
monthly_stipend_points | Buddo points stipend included with the tier |
ad_reach_multiplier | Multiplier applied to ad campaign reach |
Step 2: Create a Deployment
Create a new container deployment by specifying a subdomain, container image, tier, and optional configuration.
Endpoint
POST
/api/deploy/apps
Request Body (JSON)
| Field | Required | Description |
|---|---|---|
subdomain |
Yes | 1–32 characters, lowercase alphanumeric and hyphens. Your app will be reachable at <subdomain>.buddocloud.com. |
image |
Yes | Container image reference. Must start with harbor.buddo.xyz:4443/, docker.io/library/, or ghcr.io/. |
tier |
Yes | Deploy tier slug from GET /api/deploy/tiers |
port |
No | Container port to expose (default: 3000, range 1–65535) |
custom_domain |
No | Custom domain to bind (requires a tier where custom_domain_allowed is true) |
env_vars |
No | Key-value map of environment variables (max 50 keys) |
cURL Example
curl -X POST https://api.buddo.xyz/api/deploy/apps \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subdomain": "my-app",
"image": "harbor.buddo.xyz:4443/operators/my-app:latest",
"tier": "buddo-starter",
"port": 8080,
"env_vars": {
"NODE_ENV": "production",
"DATABASE_URL": "postgres://..."
}
}'
Success Response 201 Created
{
"deployment": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"app_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"deploy_tier_id": "...",
"container_name": "my-app-abc123",
"container_image": "harbor.buddo.xyz:4443/operators/my-app:latest",
"subdomain": "my-app",
"status": "pending",
"memory_limit_mb": 256,
"cpu_limit_millicores": 250,
"inserted_at": "2026-05-21T10:00:00Z"
}
}
The deployment starts in pending status, transitions through
deploying as the container is pulled and started, and reaches
running once healthy. Poll the status endpoint to track progress.
Error Responses
| Status | Cause |
|---|---|
401 | Missing or invalid OAuth token |
404 | Tier not found |
422 | Validation failed — invalid subdomain pattern, unsupported image registry, or unknown tier |
429 | Deployment limit reached for this tier or account |
What happens under the hood
- The API validates your request (subdomain availability, image whitelist, tier existence).
- A deployment record is created in
pendingstatus. - The platform pulls your container image on container-host-1.
- A Podman container is created with the tier's resource limits (memory, CPU).
- Caddy reverse proxy is configured to route
<subdomain>.buddocloud.comto the container's exposed port. - TLS is automatically provisioned via Caddy's built-in ACME integration.
- If a custom domain is specified, Cloudflare DNS is configured and a separate TLS certificate is provisioned.
- Health checks begin. Once the container responds, status transitions to
running.
Step 3: Domain Binding
Every deployment automatically receives a *.buddocloud.com subdomain
based on the subdomain field you provided at creation. No DNS
configuration is needed for the default subdomain.
Default subdomain
Your app is reachable at https://<subdomain>.buddocloud.com
immediately after the container reaches running status. TLS is
handled automatically.
Custom domains
If your deploy tier allows custom domains (custom_domain_allowed: true),
you can pass a custom_domain field when creating the deployment.
To use a custom domain:
- Set the
custom_domainfield in thePOST /api/deploy/appsrequest. - Add a
CNAMErecord pointing your domain to<subdomain>.buddocloud.comin your DNS provider. - The platform detects the CNAME and provisions a TLS certificate automatically via Caddy's on-demand TLS.
*.buddocloud.com subdomain works immediately.
Step 4: Monitor
Once your deployment is live, use the monitoring endpoints to check health, track status, and review the action audit log.
Get full deployment details
GET
/api/deploy/apps/{id}
Returns the complete Deployment object including status, container
info, domain configuration, health status, billing status, and timestamps.
curl https://api.buddo.xyz/api/deploy/apps/DEPLOYMENT_ID \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN"
Lightweight status polling
GET
/api/deploy/apps/{id}/status
Returns only the status and health fields — optimized for frequent polling. Rate limited to 30 requests per minute.
curl https://api.buddo.xyz/api/deploy/apps/DEPLOYMENT_ID/status \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN"
Status Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "running",
"subdomain": "my-app",
"health_status": "healthy",
"last_health_check": "2026-05-21T10:05:00Z"
}
Deployment statuses
| Status | Meaning |
|---|---|
pending | Deployment created, container not yet provisioned |
deploying | Container image is being pulled and started |
running | Container is live and passing health checks |
stopped | Container has been stopped (manually or by the platform) |
destroyed | Deployment permanently removed |
Audit logs
GET
/api/deploy/apps/{id}/logs
Returns a chronological log of all actions performed on the deployment:
create, deploy, stop,
restart, destroy, suspend,
reactivate. Each entry includes the action type, status,
timestamp, and who initiated it.
curl https://api.buddo.xyz/api/deploy/apps/DEPLOYMENT_ID/logs \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN"
Log Entry Example
{
"logs": [
{
"id": "...",
"action": "create",
"status": "completed",
"initiated_by": "7c9e6679-...",
"inserted_at": "2026-05-21T10:00:00Z",
"details": null
},
{
"id": "...",
"action": "deploy",
"status": "completed",
"initiated_by": null,
"inserted_at": "2026-05-21T10:00:05Z",
"details": null
}
]
}
List all deployments
GET
/api/deploy/apps
Returns all deployments owned by the authenticated operator. Useful for dashboards and management UIs.
curl https://api.buddo.xyz/api/deploy/apps \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN"
Step 5: Update and Restart
To update a running application, push a new version of your container image to the registry and restart the deployment. The platform will pull the latest image and replace the running container.
Restart endpoint
POST
/api/deploy/apps/{id}/restart
curl -X POST https://api.buddo.xyz/api/deploy/apps/DEPLOYMENT_ID/restart \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN"
The restart action stops the current container and starts a fresh one from the
latest image. The response returns the updated Deployment object.
The deployment briefly transitions through deploying before returning
to running.
Error Responses
| Status | Cause |
|---|---|
401 | Missing or invalid OAuth token |
403 | Deployment belongs to another operator |
404 | Deployment not found |
422 | Restart failed (e.g., deployment is already destroyed) |
Update workflow
- Build and push the new image to your registry (e.g.,
harbor.buddo.xyz:4443/operators/my-app:latest). - Call
POST /api/deploy/apps/{id}/restart. - Poll
GET /api/deploy/apps/{id}/statusuntil status returns torunning. - Verify the new version is live by hitting your app's health endpoint or checking the audit logs.
Step 6: Scale and Billing
Deployment resources and costs are governed by the tier you selected at creation. Buddo uses a two-track billing model: operators choose between paying with Buddo platform points or Bitcoin.
Buddo tier (points)
- Pay with Buddo points earned through platform activity or purchased.
- Monthly cost defined by
monthly_cost_pointson the tier. - Includes a monthly point stipend (
monthly_stipend_points). - Standard resource limits (memory and CPU as defined by the tier).
Bitcoin tier
- Pay with BTC (denominated in satoshis).
- Monthly cost defined by
monthly_cost_satson the tier. - Higher monthly point stipend than Buddo-tier equivalents.
- Elevated resource caps and full access to custom domains.
- Higher ad reach multiplier for integrated ad campaigns.
Billing cycle
Billing operates on a rolling 30-day cycle starting from
deployment creation. The deployment's billing_status field
reflects the current state. If payment lapses, the platform may suspend
the deployment — the audit log will show a suspend action.
Reactivation occurs automatically when billing is restored.
Checking tier pricing
Use GET /api/deploy/tiers
at any time to review current tier definitions, pricing, and resource limits.
See Step 1 for details.
Scaling up
To move to a higher-resource tier, destroy the current deployment and create a new one on the desired tier. The subdomain can be reused immediately after destruction.
Cleanup
When you no longer need a deployment, stop or destroy it to free resources and stop billing.
Stop a deployment
POST
/api/deploy/apps/{id}/stop
Stops the container but preserves the deployment record. The deployment can
be restarted later. Status transitions to stopped.
curl -X POST https://api.buddo.xyz/api/deploy/apps/DEPLOYMENT_ID/stop \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN"
Destroy a deployment
DELETE
/api/deploy/apps/{id}
Permanently removes the deployment, its container, and all
associated configuration. This action cannot be undone. Status transitions to
destroyed.
curl -X DELETE https://api.buddo.xyz/api/deploy/apps/DEPLOYMENT_ID \
-H "Authorization: Bearer YOUR_OAUTH_TOKEN"
Success Response 200 OK
{
"message": "Deployment destroyed",
"id": "550e8400-e29b-41d4-a716-446655440000"
}
stop if you plan to restart
later — the subdomain reservation and deployment record are preserved.
Use destroy when you are done with the deployment entirely.
Architecture
Understanding the infrastructure behind Buddo deployments helps you debug issues and design your app for the environment.
Container runtime: Podman
All operator containers run on container-host-1 using Podman (rootless, daemonless). Each deployment gets its own isolated container with resource limits (memory and CPU) enforced by the selected tier. Containers are not co-located with the core Buddo API — they run on dedicated hosting infrastructure.
Reverse proxy: Caddy
Caddy acts as the reverse proxy in front of all deployed containers. It handles:
- Routing traffic from
*.buddocloud.comsubdomains to the correct container port. - Automatic TLS provisioning via built-in ACME (Let's Encrypt).
- On-demand TLS for custom domains — certificates are issued the first time a request arrives for the domain.
- HTTPS enforcement (HTTP requests are redirected to HTTPS).
DNS: Cloudflare
The buddocloud.com zone is managed on Cloudflare. Wildcard DNS
(*.buddocloud.com) points to container-host-1. Custom domains
require the operator to add a CNAME record in their own DNS pointing to
<subdomain>.buddocloud.com.
Health checks
The platform periodically probes each running container. The
health_status and last_health_check fields on the
deployment object reflect the current state. If a container becomes
unresponsive, the platform may restart it automatically.
Image registries
Deployments accept images from three whitelisted registries:
harbor.buddo.xyz:4443/— Buddo's private Harbor registry (recommended)docker.io/library/— Official Docker Hub library imagesghcr.io/— GitHub Container Registry
API Quick Reference
All deploy endpoints require OAuth with deploy:manage scope.
For full request/response schemas, see the
Deploy API Reference.
| Endpoint | Description | Rate Limit |
|---|---|---|
GET /api/deploy/tiers |
List available deployment tiers with pricing | 30/min |
POST /api/deploy/apps |
Create a new deployment | 10/min |
GET /api/deploy/apps |
List all operator deployments | 30/min |
GET /api/deploy/apps/{id} |
Get full deployment details | 30/min |
GET /api/deploy/apps/{id}/status |
Lightweight status poll | 30/min |
GET /api/deploy/apps/{id}/logs |
Deployment audit log | 30/min |
POST /api/deploy/apps/{id}/restart |
Restart deployment container | 10/min |
POST /api/deploy/apps/{id}/stop |
Stop a running deployment | 10/min |
DELETE /api/deploy/apps/{id} |
Permanently destroy a deployment | 10/min |
Further Reading
- Deploy API Reference — Full endpoint schemas and response details
- OAuth PKCE Flow — How to obtain the
deploy:manageaccess token - JWT vs OAuth Tokens — Understanding the two auth mechanisms
- Quickstart — Register and make your first API call