Applications

Managing apps, environments, env vars, source config, and custom domains.

An application is the top-level unit. It has a name, a namespace, and an auto-generated subdomain used for routing. Creating an app also creates production and development environments automatically.

POST /api/v1/apps — Create

Body

  • name (string): Alphanumeric and hyphens
  • namespace (string): Groups apps together (e.g. production, staging)
  • description (string, optional)
  • labels (object, optional): Arbitrary key-value metadata
curl -X POST http://localhost:47080/api/v1/apps \
  -H 'Content-Type: application/json' \
  -d '{"name":"my-api","namespace":"production","description":"Main API"}'
// 201 Created
{
  "id": "uuid",
  "name": "my-api",
  "namespace": "production",
  "subdomain": "my-api-production",
  "description": "Main API",
  "labels": {},
  "default_deployment_spec": null,
  "created_at": "...",
  "updated_at": "..."
}

The subdomain is generated as {name}-{namespace} (non-alphanumeric → -). Returns 409 if the subdomain already exists.

GET /api/v1/apps — List

Query params

  • namespace (string, optional): Filter by namespace
  • page (number): Default 1
  • page_size (number): Default 20, max 100
  • sort_by (string): name, namespace, subdomain, created_at, updated_at
  • sort_order (string): asc or desc
curl "http://localhost:47080/api/v1/apps?namespace=production&sort_by=name"
{ "data": [ { ...app } ], "total": 42, "page": 1, "page_size": 20 }

GET /api/v1/apps/

Fetch by UUID.

GET /api/v1/apps//

Fetch by human-readable key — useful when you know the name but not the UUID.

curl http://localhost:47080/api/v1/apps/production/my-api

GET /api/v1/apps/by-subdomain/

Fetch by subdomain. Used by the proxy for routing lookups.

PUT /api/v1/apps/ — Update

All fields are optional; omit to keep the current value.

Body

  • description (string, optional)
  • labels (object, optional)
  • default_deployment_spec (object, optional): New deployments inherit these when the create payload doesn't specify them
    • replicas (number)
    • resources: { "cpu": "500m", "memory": "256Mi" }
    • max_runtime_secs (number or null)
curl -X PUT http://localhost:47080/api/v1/apps/$APP_ID \
  -H 'Content-Type: application/json' \
  -d '{"default_deployment_spec":{"replicas":2,"resources":{"cpu":"500m","memory":"256Mi"}}}'

DELETE /api/v1/apps/

Stops all running tasks first, then deletes the app and its data. Returns 204 No Content.

Also available as DELETE /api/v1/apps/{namespace}/{name}.


Environments

Environments (production, development, or any custom slug) are created automatically when you create an app. They segment deployments and env vars.

GET /api/v1/apps//environments

[
  { "slug": "production", "description": "Live production deployment" },
  { "slug": "development", "description": "Latest deployment (main subdomain)" }
]

Environment variables

Env vars are attached to an app and optionally scoped to an environment slug. When a deployment is created, vars for that environment plus unscoped vars are merged in — environment-specific vars win on conflict.

Keys are uppercased automatically. Setting the same key again overwrites it (upsert).

POST /api/v1/apps//env — Set a var

Body

  • key (string): Alphanumeric and underscores only; auto-uppercased
  • value (string)
  • environment (string, optional): Scope to a specific environment. Omit or use "" to apply to all environments
  • is_secret (boolean, optional): Secret values are masked in list responses
# Applies to all environments
curl -X POST http://localhost:47080/api/v1/apps/$APP_ID/env \
  -H 'Content-Type: application/json' \
  -d '{"key":"LOG_LEVEL","value":"info"}'
 
# Production only
curl -X POST http://localhost:47080/api/v1/apps/$APP_ID/env \
  -H 'Content-Type: application/json' \
  -d '{"key":"DATABASE_URL","value":"postgres://...","environment":"production","is_secret":true}'

GET /api/v1/apps//env — List vars

Use ?environment=production to filter. Secrets are masked as ab***cd.

{
  "data": [
    { "id": "uuid", "key": "DATABASE_URL", "value": "po***db", "environment": "production", "is_secret": true }
  ]
}

DELETE /api/v1/apps//env/

Use ?environment=production to delete a scoped var. Without the query param, deletes the unscoped (all-environments) version of the key.


Source config 🔒

Source config connects an app to a Git repository so POST .../deploy/trigger can build and deploy automatically. Only github is supported for triggered deploys today.

POST /api/v1/apps//source-config — Create / replace

Body

  • source_type (string): "github", "gitlab", or "manual"
  • config (object): For GitHub — { "owner": "myorg", "repo": "my-app", "branch": "main" }
  • webhook_secret (string, optional): Used to verify incoming GitHub webhook payloads
curl -X POST http://localhost:47080/api/v1/apps/$APP_ID/source-config \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "source_type": "github",
    "config": {"owner":"myorg","repo":"my-app","branch":"main"},
    "webhook_secret": "whsec_abc..."
  }'
// 201 Created
{
  "id": "uuid", "app_id": "uuid", "source_type": "github",
  "config": { "owner": "myorg", "repo": "my-app", "branch": "main" },
  "has_webhook_secret": true, "created_at": "...", "updated_at": "..."
}

GET /api/v1/apps//source-config

Returns current config. Raw webhook secret is never returned; has_webhook_secret indicates whether one is set.

PUT /api/v1/apps//source-config — Update

Send only the fields to change — config and/or webhook_secret.

DELETE /api/v1/apps//source-config

204 No Content.


Custom domains

POST /api/v1/apps//custom-domains — Add

Body

  • domain (string): e.g. api.mycompany.com
  • path_prefix (string): e.g. "/"
curl -X POST http://localhost:47080/api/v1/apps/$APP_ID/custom-domains \
  -H 'Content-Type: application/json' \
  -d '{"domain":"api.mycompany.com","path_prefix":"/"}'

Point your DNS (A or CNAME) to the platform proxy. The proxy routes by Host header.

GET /api/v1/apps//custom-domains

List custom domain routes for the app.

DELETE /api/v1/apps//custom-domains/

204 No Content.

See also