App resources API
Routes nested under an app. {appId} is the app’s id. Permission levels refer
to the app’s team (see API overview).
Domains
Section titled “Domains”| Method | Path | Permission | Body | Returns |
|---|---|---|---|---|
GET |
/apps/{appId}/domains/ |
Viewer | {results} |
|
POST |
/apps/{appId}/domains/ |
Developer | {hostname, isPrimary?} |
The domain (ssl_status: "none") |
POST |
/apps/{appId}/domains/{id}/ssl |
Developer | {detail: "Certificate issuance queued."} |
|
DELETE |
/apps/{appId}/domains/{id} |
Developer | {detail: "Domain removed."} |
Domain objects are rows: id, app_id, hostname, is_primary,
is_verified, verification_token, ssl_status (none, pending,
issued, expired, failed), ssl_expires_at, ssl_issuer, created_at.
When to use: add the domain once DNS points at the server, then call
/ssl. Only web apps accept domains (400 otherwise). The hostname must
be a valid DNS name. It’s lowercased and must not be attached to any app
already (409 domain_already_attached or 409 domain_in_use). Adding and
removing a domain rewrites the vhost. Issuing runs certbot --nginx through
the worker. See Custom domains and TLS.
Cron jobs
Section titled “Cron jobs”| Method | Path | Permission | Body / query | Returns |
|---|---|---|---|---|
GET |
/apps/{appId}/cron/ |
Viewer | {results}: jobs |
|
GET |
/apps/{appId}/cron/preview |
Authenticated | Query schedule |
{schedule, next: [5 ISO times]}, or 400 invalid_schedule |
POST |
/apps/{appId}/cron/ |
Developer | {name, schedule, command, timeoutSeconds?, enabled?} |
The job |
PATCH |
/apps/{appId}/cron/{jobId} |
Developer | Any of the create fields | The job |
DELETE |
/apps/{appId}/cron/{jobId} |
Developer | {detail}. Deletes its runs too. |
|
POST |
/apps/{appId}/cron/{jobId}/run |
Developer | The run. 409 if a run is still going. |
|
GET |
/apps/{appId}/cron/{jobId}/runs |
Developer | {results}: the last 50 runs, newest first |
| Field | Rules |
|---|---|
name |
Required, ≤ 100 characters. |
schedule |
Required. 5-field cron expression or @hourly, @daily, @weekly, @monthly, @yearly, in UTC. |
command |
Required, ≤ 4000 characters. |
timeoutSeconds |
1 to 3600, default 300. |
enabled |
Default true. |
Jobs (camelCase): id, appId, name, schedule, command,
timeoutSeconds, enabled, nextRunAt, lastRunAt, lastStatus,
createdAt. Runs: id, jobId, execId, trigger, status (running,
succeeded, failed, timed_out, skipped), exitCode, output (last 200
lines), startedAt, finishedAt.
When to use: recurring maintenance in the app’s environment. An app can
have at most 20 jobs. Stream a run’s live output on
/ws/apps/{appId}/exec/{execId}. See Cron jobs.
Metrics
Section titled “Metrics”| Method | Path | Permission | Query | Returns |
|---|---|---|---|---|
GET |
/apps/{appId}/metrics/ |
Viewer | minutes (default 60) |
{app: {id, name, status}, samples} |
Samples are rows, oldest first: id, app_id, cpu_percent (percent of one
core), mem_bytes, rss_bytes, sampled_at. For the latest sample of every
app at once, use GET /apps/metrics-summary
(Apps API).
Runtime logs
Section titled “Runtime logs”| Method | Path | Permission | Query | Returns |
|---|---|---|---|---|
GET |
/apps/{appId}/runtime-logs/ |
Viewer | lines (1 to 2000, default 200) |
{lines: [...]}, plus error if the agent failed, or detail when the app was never deployed |
When to use: a one-shot tail for scripts and AI assistants that can’t
hold a WebSocket open. For a live stream, use /ws/apps/{appId}/logs. Times
out with 504 logs_timeout after 15 seconds. Build logs are on the
Deployments API.
Linked storage buckets
Section titled “Linked storage buckets”| Method | Path | Permission | Body | Returns |
|---|---|---|---|---|
GET |
/storage/apps/{appId}/links |
Viewer | {results}: {id, appId, bucketId, envPrefix, bucketName, providerName, providerKind, envVars, createdAt} |
|
POST |
/storage/apps/{appId}/links |
Superuser | {bucketId, envPrefix?} (default S3, ≤ 32 characters) |
{id, appId, bucketId, envPrefix} |
DELETE |
/storage/apps/{appId}/links/{linkId} |
Developer | {detail: "Bucket unlinked."} |
Linking writes these env vars on the app (with your prefix):
S3_ENDPOINT, S3_REGION, S3_BUCKET, S3_ACCESS_KEY, S3_SECRET_KEY,
S3_PUBLIC_URL, S3_FORCE_PATH_STYLE. Unlinking removes them. Redeploy for
either to take effect. Linking is superuser-only because any developer can
read an app’s env vars. Buckets themselves are on the
Infrastructure API.