Apps API
Register Shell and standalone apps, publish releases, and promote across environments.
Base path: /v1/workspaces/{workspace_id}/apps
Apps are optional product packaging. Do not create an app solely to deploy a workload — use the Coderunners API. app_kind=coderunner is rejected on create.
See also: Apps
List apps
GET /v1/workspaces/{workspace_id}/apps?kind=product| Query | Values |
|---|---|
kind | product (default: shell_federated and standalone), shell_federated, standalone, all. The legacy value coderunner is also accepted; anything else returns 422 |
include_archived | true to include archived apps. Default false |
Returns at most 200 apps.
Permission: read
Create app
POST /v1/workspaces/{workspace_id}/appsPermission: write (workspace site auth is not required)
| Body field | Required | Notes |
|---|---|---|
name | Yes | Display name |
slug | Yes | Unique in workspace. Lowercase letters, digits and hyphens, 1 to 63 characters; a duplicate returns 409 |
app_kind | No | shell_federated (default) or standalone |
environment_id | No | Target environment. Defaults to the dev environment (or the only active one) |
primary_coderunner_id | Standalone | Primary service coderunner. Must be in this workspace (404 otherwise), not archived (409), and a service workload (400) |
manifest | No | JSON manifest |
git_repo_url | No | Source repo metadata |
Get / update / delete
| Method | Path | Permission |
|---|---|---|
GET | /v1/workspaces/{workspace_id}/apps/{app_id} | read |
PATCH | same — name, manifest, git_repo_url, primary_coderunner_id | write |
DELETE | same — archives the app. Returns 204 | delete |
POST | …/apps/{app_id}/restore — un-archives the app. 409 if the app is not archived | delete |
GET | …/apps/by-slug?slug= — Shell config for a shell_federated app by slug (404 if not found) | read |
App access
GET /v1/workspaces/{workspace_id}/apps/{app_id}/access
PUT /v1/workspaces/{workspace_id}/apps/{app_id}/accessControls who can launch the app in the Shell. The PUT replaces the whole setting:
{
"visibility": "restricted",
"grants": [{ "role": "editor", "action": "read" }]
}visibilityisworkspace(default; anyone who can read the workspace can launch the app) orrestricted(only the site roles listed ingrants).- Each grant names a workspace site role.
actionis alwaysread. - The built-in
adminrole is a role like any other. On arestrictedapp, listadminingrantsif admins should launch it; if you leave it out, admins lose access.
Permission: ddl on the workspace. Site users get 403, whatever their role, admin included; manage app access from the Client Portal or with a builder token.
Releases (Shell federated)
| Method | Path | Purpose | Permission |
|---|---|---|---|
POST | …/apps/{app_id}/releases/upload-url | Init upload (bundle: remote_entry | zip) | write |
PUT | …/releases/{release_id}/content | Upload bytes (≤32 MiB). Returns 204 | write |
POST | …/releases/{release_id}/finalize | Publish | write |
GET | …/releases | List | read |
GET | …/releases/current | Current published (404 if none) | read |
Releases apply to shell_federated apps only (400 for other kinds, 410 for an archived app).
The upload-url body takes bundle (default remote_entry), an optional label (up to 120 characters) and a required size_bytes: the exact size you will upload, greater than 0 and at most 32 MiB (33,554,432 bytes). A missing size_bytes returns 422 and an oversized one returns 413. The size is checked again on finalize.
For a zip bundle, the archive is extracted on finalize. The extracted contents can't exceed 256 MiB or 2,000 entries; an archive over either limit is refused with 400. A zip can be finalized once, so a refused archive needs a new upload. Finalize returns 409 if no remoteEntry.js is found in the upload.
Custom domains
Custom domains belong to Apps, not Coderunners: a standalone App's domains point at its primary_coderunner_id. These routes work for apps of kind standalone (and legacy coderunner apps); any other app kind returns 400, an archived app 410:
| Method | Path | Permission |
|---|---|---|
GET | /v1/workspaces/{workspace_id}/apps/{app_id}/coderunner/domains | read |
POST | …/apps/{app_id}/coderunner/domains | write (201) |
DELETE | …/apps/{app_id}/coderunner/domains/{domain} | write (204) |
POST | …/apps/{app_id}/coderunner/domains/{domain}/verify | write |
GET / PUT | …/apps/{app_id}/coderunner/public | read / write |
POST body: { "domain": "example.com" } (a bare hostname, up to 253 characters). 409 when the domain is already added or collides with a branded host.
Each domain item has domain, status (pending, verifying, verified, active or error), cname_target (create a CNAME from your domain to this host; apex domains need ALIAS/ANAME), verification_record ({type, name, value}: a DNS TXT record that proves you own the domain), last_checked_at and detail (the result of the last check). verify re-checks DNS and returns {domain, status, verified, detail}. The …/public routes behave like the Coderunner ones.
CLI: gf domains ls|add|rm|verify --app <id|slug>.
Compare and promote
GET /v1/workspaces/{workspace_id}/apps/compare?source_environment_id=&target_environment_id=
POST /v1/workspaces/{workspace_id}/apps/promotePromote body: source_environment_id, target_environment_id, pairs[] (source_app_id, optional target_app_id / source_release_id), optional dry_run.
Permission: compare read, promote write
Shell config
GET /v1/workspaces/{workspace_id}/apps/{app_id}/shell-configAuthenticated bootstrap metadata for Shell hosts. Permission: read
Public by-slug bootstrap lives under /v1/public/… — see API authentication and Shell API reference.