v1 · api.getctrl.dev
All /v1/* endpoints require a Bearer token in the Authorization header:
Authorization: Bearer <api_key>
Tokens are issued via GitHub OAuth at /auth/github. Internal routes (/internal/*) are not publicly accessible.
| Plan | vCPU | RAM | Disk | Price |
|---|---|---|---|---|
hobby | 1 | 2 GB | 30 GB | $5/mo |
builder | 2 | 4 GB | 60 GB | $15/mo |
pro | 4 | 8 GB | 100 GB NVMe | $75/mo |
scale | 8 | 16 GB | 200 GB NVMe | $140/mo |
Response 200:
[
{
"app_id": "my-api",
"name": "My API",
"status": "running",
"region": "us-east",
"subdomain": "my-api.getctrl.dev",
"created_at": "2026-05-01T12:00:00Z"
}
]
Request body:
{
"name": "My API",
"repo": "my-repo",
"branch": "main",
"image_ref": "ghcr.io/acme/my-api:latest", // or use repo_url instead
"repo_url": null, // git clone URL (alternative to image_ref)
"region": "us-east",
"exposed_port": 8080,
"vcpu_count": 1,
"mem_size_mb": 2048,
"disk_size_mb": 30720,
"env_vars": [["PORT", "8080"]],
"add_database": false
}
Response 201:
{
"app_id": "my-api",
"vm_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "starting",
"region": "us-east",
"node_id": "us-1",
"subdomain": "my-api.getctrl.dev"
}
Errors:
app_id already in useResponse 200:
{
"app_id": "my-api",
"name": "My API",
"vm_id": "550e8400-...",
"status": "running",
"region": "us-east",
"node_id": "us-1",
"image_ref": "ghcr.io/acme/my-api:latest",
"exposed_port": 8080,
"repo": "my-repo",
"branch": "main",
"subdomain": "my-api.getctrl.dev",
"repo_full_name": "acme/my-repo",
"env_vars": "[["PORT","8080"]]",
"created_at": "2026-05-01T12:00:00Z"
}
Request body:
{
"env_vars": [["PORT", "8080"], ["NODE_ENV", "production"]]
}
Response 200:
{ "ok": true, "redeployed": true }
Response 200:
{ "ok": true }
Query parameters:
| Param | Default | Description |
|---|---|---|
tail | 100 | Number of lines (max 1000) |
Response 200:
{ "lines": ["[2026-05-01 12:00:00] Server listening on :8080", "..."] }
Response 200:
[
{
"id": "deploy-uuid",
"commit_sha": "abc1234",
"commit_msg": "fix: login bug",
"trigger": "push",
"status": "success",
"duration_ms": 45000,
"created_at": "2026-05-01T12:00:00Z"
}
]
Request body:
{ "deploy_id": "deploy-uuid" }
Response 200:
{ "ok": true, "deploy_id": "new-deploy-uuid" }
Errors:
Query parameters:
| Param | Values | Default |
|---|---|---|
period | 1h, 24h, 7d | 1h |
Response 200:
{
"period": "1h",
"points": [
{
"timestamp": "2026-05-01T12:00:00Z",
"cpu": 12.5,
"memory_mb": 50.0,
"rx_kb": 1024.0,
"tx_kb": 512.0
}
]
}
Errors:
DATABASE_URL env var.Response 201:
{
"database_id": "my-api-db",
"db_name": "my_api_db",
"db_user": "u_abc123",
"host": "db-1.nodes.getctrl.dev",
"port": 3306,
"connection_string": "mysql://u_abc123:pass@host:3306/my_api_db",
"status": "active"
}
Errors:
DATABASE_URL from app env vars.Response 200:
[
{
"id": "backup-uuid",
"size_bytes": 1048576,
"status": "completed",
"created_at": "2026-05-01T03:00:00Z"
}
]
Request body:
{ "backup_id": "backup-uuid" }
Errors:
Response 200:
{
"id": "acc-uuid",
"github_login": "octocat",
"plan": {
"id": "hobby",
"display_name": "Hobby",
"vcpu_limit": 1,
"mem_limit_mb": 2048,
"disk_limit_mb": 30720
},
"usage": {
"vcpu": 1,
"mem_mb": 2048,
"disk_mb": 30720
},
"subscription_status": "active",
"created_at": "2026-04-01T00:00:00Z"
}
Response 200:
[
{
"full_name": "octocat/my-repo",
"name": "my-repo",
"private": false,
"default_branch": "main",
"language": "TypeScript",
"pushed_at": "2026-05-01T12:00:00Z"
}
]
?ref=branch query param.Response 200:
{ "exists": true }
ctrl_session cookie (JWT, 7-day expiry) and redirects to dashboard.