AI Agent API Guide
A complete reference for AI coding agents, LLMs, and automation tools to interact with the Better-PaaS API.
Better-PaaS is designed to be fully programmable. This guide gives AI coding agents, CI/CD tools, and automation scripts everything they need to deploy apps, read logs, manage databases, and monitor health - all through a clean JSON REST API.
You can authenticate with either your admin token or a scoped agent token. Agent tokens are recommended for any automated tool - they can be limited to specific actions and revoked independently.
Recommended: connect from your laptop with the paas CLI:
paas connect <dashboard-url> # browser authorization
paas setup # wire up Cursor / Claude Code MCPRestart your editor, then ask in plain English ("list my apps", "show logs for X"). For manual token creation and scope reference, see Agent Access & Audit Logs.
Using with AI editors (MCP)
The CLI includes a built-in MCP server (paas mcp) that Cursor, Claude Code,
and other MCP clients can call directly - no curl in chat.
| Step | Command |
|---|---|
| 1. Connect | paas connect https://paas.example.com |
| 2. Configure editor | paas setup |
| 3. Restart editor | Quit and reopen Cursor or Claude Code |
| 4. Ask in chat | "List my Better-PaaS apps", "Redeploy my-api", etc. |
MCP tools available today: paas_list_apps, paas_list_projects, paas_get_app,
paas_deploy, paas_redeploy, paas_get_logs, paas_status. See the full list
and roadmap in PaaS CLI - MCP tools.
If your tool does not support MCP, use the terminal fallback:
eval "$(paas env)"Then the AI can call the REST API with $PAAS_API_URL and $PAAS_TOKEN. The
endpoints below document that path.
Authentication
Every API endpoint requires a Bearer token:
Authorization: Bearer <token>Two token types:
| Token | Use when | Permissions |
|---|---|---|
| Admin token | Dashboard login, managing agents, viewing audit logs | Full access to everything |
| Agent token | CI/CD, AI assistants, monitoring scripts, automation | Limited to assigned scopes |
Admin token
Generated on first run. Retrieve it anytime:
cd ~/better-paas/backend && ./server tokenAgent token (recommended for automation)
Fastest: use the paas CLI:
paas connect https://paas.example.com
paas setup # MCP for Cursor / Claude Code - restart editor after
paas statusManual: create a scoped token via the API:
curl -X POST http://localhost:8080/api/agents/create \
-H "Authorization: Bearer <admin_token>" \
-H "Content-Type: application/json" \
-d '{
"name": "My Automation",
"scopes": ["apps:read", "apps:write", "deploy:trigger", "logs:read"]
}'The response includes a bpagt_... token shown once. Save it securely.
WebSocket authentication
WebSocket endpoints (for live logs and stats) authenticate with a short-lived ticket:
# Step 1: mint a ticket (requires any valid token)
curl -X POST http://localhost:8080/api/auth/ws-ticket \
-H "Authorization: Bearer <token>"
# → { "ticket": "abc123...", "expiresIn": 60 }
# Step 2: connect with the ticket
ws://YOUR_SERVER:8080/ws/logs?ticket=abc123...Core API Endpoints
Apps
List all apps
GET /api/apps
Authorization: Bearer <token>Response:
[
{
"id": "abc123def4",
"name": "my-node-app",
"status": "running",
"gitRepo": "https://github.com/user/my-node-app",
"branch": "main",
"port": 3000,
"url": "http://abc123def4.192.168.1.10.sslip.io",
"domains": ["node-app.example.com"],
"createdAt": "2026-06-01T12:00:00Z",
"activeCommit": "a1b2c3d",
"activeCommitMsg": "feat: add user auth"
}
]Get a single app
GET /api/apps/get?id=<app-id>
Authorization: Bearer <token>Returns full app details including runtime configuration, domains, volumes, and latest deployment info. Same shape as items in the list endpoint.
Deploy a new app
POST /api/deploy
Authorization: Bearer <token>
Content-Type: application/jsonBody parameters:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | App name (lowercase letters, digits, hyphens; 2–40 chars) |
gitRepo | string | Yes | Git clone URL |
branch | string | Yes | Branch to deploy |
envVars | object | No | Environment variables as key-value strings |
buildCommand | string | No | Override the build command |
startCommand | string | No | Override the start command |
domains | string[] | No | Custom domains |
memory | string | No | Memory limit (e.g. "512m", "1g") |
cpus | string | No | CPU limit (e.g. "0.5", "2") |
volumes | string[] | No | Persistent volumes ("name:/container/path") |
healthPath | string | No | HTTP health check path (default: TCP probe) |
Example:
{
"name": "marketing-site",
"gitRepo": "https://github.com/org/marketing",
"branch": "main",
"envVars": {
"NODE_ENV": "production",
"API_TIMEOUT": "5000"
},
"memory": "512m",
"healthPath": "/health"
}Redeploy an existing app
POST /api/apps/redeploy
Authorization: Bearer <token>
Content-Type: application/json{
"id": "abc123def4",
"noCache": false
}Stop / Start / Delete
POST /api/apps/stop
POST /api/apps/start
POST /api/apps/delete
Authorization: Bearer <token>
Content-Type: application/json{ "id": "abc123def4" }Rollback
POST /api/apps/rollback
Authorization: Bearer <token>
Content-Type: application/json{
"id": "abc123def4",
"deploymentId": "dep_xyz789"
}Update app configuration
POST /api/apps/update
Authorization: Bearer <token>
Content-Type: application/json{
"id": "abc123def4",
"envVars": { "API_KEY": "new-value" },
"memory": "1g",
"domains": ["app.example.com"]
}Runtime logs
GET /api/apps/runtime-logs?id=<app-id>&lines=100
Authorization: Bearer <token>Response:
{
"logs": ["line 1", "line 2", "line 3"]
}Per-app metrics
GET /api/metrics/apps
Authorization: Bearer <token>Response:
[
{
"appId": "abc123def4",
"name": "my-node-app",
"cpuPercent": 12.5,
"memUsageMb": 128.0,
"memLimitMb": 512.0,
"memPercent": 25.0
}
]Add-ons (Databases & Caches)
List all add-ons
GET /api/addons
Authorization: Bearer <token>Get a single add-on
GET /api/addons/get?id=<addon-id>
Authorization: Bearer <token>Create an add-on
POST /api/addons/create
Authorization: Bearer <token>
Content-Type: application/json{
"name": "prod-db",
"type": "postgres"
}Supported types: postgres, redis, mysql.
When you attach a database to an app, Better-PaaS automatically injects
connection env vars like DATABASE_URL and REDIS_URL into the app
container. No custom networking needed.
Attach / Detach
POST /api/addons/attach
POST /api/addons/detach
Authorization: Bearer <token>
Content-Type: application/json{
"addonId": "addon_123",
"appId": "abc123def4"
}Database operations (Postgres/MySQL only)
POST /api/addons/db/query
Authorization: Bearer <token>
Content-Type: application/json{
"addonId": "addon_123",
"query": "SELECT * FROM users LIMIT 10"
}Other endpoints: /api/addons/db/tables, /api/addons/db/columns, /api/addons/db/row/insert, /api/addons/db/row/update, /api/addons/db/row/delete.
Projects
GET /api/projects
GET /api/projects/get?id=<id>
POST /api/projects/create { "name": "my-project" }
POST /api/projects/rename { "id": "...", "name": "new-name" }
POST /api/projects/delete { "id": "..." }Servers
GET /api/servers
GET /api/server/info
POST /api/servers/create
POST /api/servers/delete { "id": "..." }
POST /api/servers/test { "id": "..." }Cron Jobs
GET /api/cron
POST /api/cron/create
POST /api/cron/update
POST /api/cron/delete
POST /api/cron/run { "id": "..." }Backups
GET /api/backups
POST /api/backups/create
POST /api/backups/restore
POST /api/backups/deleteSystem
GET /api/system/version
GET /api/health
POST /api/docker/prune
POST /api/system/update/apply
GET /api/deployments/historyGuidelines for apps deployed on Better-PaaS
1. Bind to the injected PORT
Better-PaaS passes the PORT environment variable. Do not hardcode a port.
Node.js / Express:
const port = process.env.PORT || 3000;
app.listen(port, '0.0.0.0', () => console.log(`Listening on ${port}`));Python / FastAPI:
import os
import uvicorn
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8000))
uvicorn.run("main:app", host="0.0.0.0", port=port)2. Containers are ephemeral
Each deploy creates a fresh container. For persistent state:
- Logs: Write to stdout/stderr. Better-PaaS captures and streams them automatically.
- Files / uploads / SQLite: Mount a persistent volume via the API:
"volumes": ["mydata:/data"].
3. Commit lockfiles
Nixpacks detects your language from lockfiles. Always commit:
- JavaScript:
package-lock.json,pnpm-lock.yaml, oryarn.lock - Python:
requirements.txtorpoetry.lock - Go:
go.sum - Ruby:
Gemfile.lock
4. Add a health check endpoint
Better-PaaS does a TCP probe by default. For faster, safer zero-downtime deploys, add an HTTP health endpoint:
app.get('/health', (req, res) => {
res.status(200).send('ok');
});Then set healthPath: "/health" when deploying.
Rate limits and errors
- Failed authentication attempts from an IP trigger an escalating lockout (HTTP
429withRetry-After). - Request bodies are capped at 2 MiB.
- All errors return JSON:
{ "error": "App not found" }