Apps API
Routes under /apps. Deployments, domains, cron jobs, metrics, logs and the
webhook are on Deployments API and
App resources API.
| Method | Path | Permission | Body / query | Returns |
|---|---|---|---|---|
GET |
/apps/ |
Authenticated | Query projectId? |
{results}: apps you can see |
POST |
/apps/ |
Developer on the project’s team | Create body | The app (status: "created") |
GET |
/apps/metrics-summary |
Authenticated | {results}: latest {appId, name, status, cpuPercent, memBytes, memoryMbLimit, cpuQuotaPercent, sampledAt} per running app, samples under 5 minutes old |
|
GET |
/apps/limits |
Authenticated | {cpuCores, maxCpuQuotaPercent} |
|
GET |
/apps/{id} |
Viewer | The app | |
PATCH |
/apps/{id} |
Developer (Admin on both teams to move across teams) | Update body | The app |
DELETE |
/apps/{id} |
Admin | {detail: "App removal requested."} |
When to use: create an app once, then deploy it. PATCH changes settings
that take effect on the next deploy. The exceptions are the static settings
(staticSpa, staticRoot) and media settings (mediaEnabled,
mediaMaxUploadMb), which re-render the Nginx vhost immediately without a
rebuild. DELETE tears down the unit, vhost, firewall rule, Linux user and
files, then the app’s rows.
Create body
Section titled “Create body”| Field | Type | Default | Description |
|---|---|---|---|
projectId |
int | required | Project to create the app in. |
name |
string | required | Up to 60 characters. |
sourceType |
string | required | git, binary or zip. Fixed after creation. |
applicationId |
int | Installed runtime to target. Preferred. | |
runtime |
string | Runtime key (dart, go, rust, node, bun, python, celery, zig, binary, static), as an alternative to applicationId. The runtime must be installed. |
|
deploymentMode |
string | runtime’s default | build_execute, direct_run or static_publish. Must be one the runtime supports. |
exposeMode |
string | web |
web, tcp, internal or process. Fixed after creation. Static apps are always web. Celery can’t be process. |
internalPort |
int | 1024 to 65535, unique on the host. Required except for static and process. Passed to the app as PORT. |
|
publiclyReachable |
bool | true for tcp |
Open the tcp app’s port in ufw. |
gitUrl |
string | https://, ssh://, git:// or user@host:path. |
|
gitBranch |
string | repo default | Branch or tag. |
sourceSubdir |
string | repo root | Subdirectory to build and run from. |
deployKeyId |
int | One of your SSH keys, for private repos. | |
buildCommand |
string | runtime’s default | A single command (no |, &, ;, $, <, > or backticks). |
startCommand |
string | runtime’s default | Same character rules. Required for tcp, internal and process apps on python, node, bun and rust. |
healthCheckPath |
string | Path probed over HTTP after each deploy (web apps), for example /healthz. |
|
memoryMbLimit |
int | 256 | 32 to the host’s RAM in MB. |
cpuQuotaPercent |
int | 50 | 1 to cores × 100 (percent of one core). |
tasksLimit |
int | 100 | 16 to 16384. |
dartVersion, goVersion, rustVersion, nodeVersion, bunVersion, pythonVersion |
string | runtime default | Toolchain version pin, such as 3.5.4, 22.12.0 or stable. |
pythonMode |
string | wsgi |
wsgi or asgi. |
wsgiApp |
string | Gunicorn app target, such as myproject.wsgi:application. |
|
gunicornWorkers, gunicornThreads, gunicornTimeout |
int | 4, 1, 120 | Gunicorn tuning. |
gunicornBind, gunicornExtraArgs |
string | Bind override and extra flags. | |
celeryApp, celeryQueues, celeryExtraArgs |
string | Celery app path, comma-separated queues, extra flags. | |
celeryWorkerCount, celeryConcurrency |
int | 2, 4 | Celery workers and concurrency per worker. |
celeryBeatEnabled |
bool | false | Run Celery beat. |
staticRoot |
string | Directory to serve for static, such as dist. |
|
staticSpa |
bool | false | Fall back to index.html. |
mediaEnabled |
bool | false | Persistent shared/media, served at /media/. |
mediaMaxUploadMb |
int | 25 | Nginx client_max_body_size. |
Creation also checks the team quota.
Example
curl -sX POST https://panel.example.com/apps/ \ -H 'Authorization: Bearer gsl_xxxxxxxxxxxxxxxx' -H 'Content-Type: application/json' \ -d '{"projectId": 12, "name": "billing-api", "runtime": "dart", "sourceType": "git", "gitUrl": "https://github.com/acme/billing-api.git", "internalPort": 4001, "healthCheckPath": "/healthz"}'Update body
Section titled “Update body”Any subset of: name, projectId, gitUrl, gitBranch, sourceSubdir
("" clears it), buildCommand, startCommand, healthCheckPath,
releasesToKeep (1 to 50, default 5), memoryMbLimit, cpuQuotaPercent,
tasksLimit, the version pins, the Python, Gunicorn and Celery fields,
staticRoot, staticSpa, mediaEnabled, mediaMaxUploadMb,
deployKeyId, internalPort. sourceType and exposeMode can’t be
changed.
App object
Section titled “App object”The app is returned as a database row, so its keys are snake_case: id,
project_id, name, slug, linux_user (app_<6 chars>), work_dir,
internal_port, expose_mode, publicly_reachable, application_id,
runtime, deployment_mode, source_type, git_url, git_branch,
build_command, start_command, health_check_path, releases_to_keep,
memory_mb_limit, cpu_quota_percent, tasks_limit, the runtime-specific
settings, status, last_deployed_at, created_at and updated_at.
status is one of created, building, running, stopped, failed,
crashed or deleting.
Lifecycle
Section titled “Lifecycle”| Method | Path | Permission | Returns |
|---|---|---|---|
POST |
/apps/{id}/start |
Developer | {detail: "Start requested."} |
POST |
/apps/{id}/restart |
Developer | {detail: "Restart requested."} |
POST |
/apps/{id}/stop |
Admin | {detail: "Stop requested."} |
When to use: these act on the existing build and unit. A restart doesn’t re-read env vars from the panel. Redeploy for that.
Console commands
Section titled “Console commands”| Method | Path | Permission | Body | Returns |
|---|---|---|---|---|
POST |
/apps/{id}/exec |
Developer | {command} (up to 4000 characters) |
{execId} |
The command runs once as the app’s Linux user, in its directory, with its env
vars (and the virtualenv activated for Python and Celery). Stream the output
on /ws/apps/{id}/exec/{execId}. Use it for migrations and one-off
maintenance.
Network exposure
Section titled “Network exposure”| Method | Path | Permission | Body | Returns |
|---|---|---|---|---|
POST |
/apps/{id}/network |
Developer | {publiclyReachable} |
The app |
Only for tcp apps. Opens or closes ufw for the app’s port with no rebuild
or restart. Re-sending the same value retries a failed reconcile.
Env vars
Section titled “Env vars”| Method | Path | Permission | Body | Returns |
|---|---|---|---|---|
GET |
/apps/{id}/envs |
Viewer | {results}: {id, app_id, name, value, is_secret, updated_at}. value is left out for secrets. |
|
POST |
/apps/{id}/envs |
Developer | {name, value?, isSecret?} |
The env var. Upserts by name. Leave out value to keep the stored one. |
POST |
/apps/{id}/envs/bulk |
Developer | {entries: [{name, value, isSecret?}, …]} |
{imported} |
DELETE |
/apps/{id}/envs/{envId} |
Developer | {detail} |
Names must be identifiers ([A-Za-z_][A-Za-z0-9_]*), at most 200
characters. Values are encrypted at rest and written to the app’s .env on
the next deploy. See Env vars and secrets.