Resource guide
An app binds a folder to a process
App registration connects a workspace path, start command, port, and stable slug. An optional name
is the human-facing label; when it is unset, clients display the registered folder name. An optional
icon is a safe path relative to that app folder, such as icon.png or assets/icon.png—it is not
an image URL or embedded bytes. Keep the command reproducible from the registered folder and choose
visibility separately from process configuration. The API returns the generated
standalone canonicalUrl; clients should use that address rather than construct or persist a
second app identity. An active custom hostname becomes this standalone address. The generated
https://<app>--<workspace>.edge.duet.so/ address keeps working.
{
"path": "apps/status",
"command": "bun run start",
"apiScopes": ["services"],
"port": 4173,
"slug": "status",
"name": "Status Board",
"icon": "assets/icon.png"
}apiScopes is the app server's least-privilege declaration, not a list of features the UI happens
to show. Declare only the capabilities required by Duet API routes the server actually calls, and
send [] when it calls none. The capability grammar and credential boundaries live in
API keys and scopes; admin is deliberately unavailable to apps.
Duet does not add an install-time consent step. Declared scopes are visible before and after an app is installed, with elevated access called out; a workspace removes that authority by disabling or uninstalling the app, not by maintaining a second approval record.
Runtime authority stays outside the drive
After registration, Duet mints a hidden key for each app row with a non-empty declaration in that
workspace. Only the spawned service receives DUET_APP_API_KEY and DUET_API_URL; install commands
do not receive the key. Read both from the process environment and keep the key in memory. Never
write it to source, .env*, SQLite, logs, or another drive path: drive contents sync to devices and
can be shared or published.
Changing apiScopes replaces stale authority and restarts that app with the new key. Disabling or
deleting the app revokes its key. The platform owns refresh and recovery, so app code should treat
the value as replaceable rather than cache it.
Reconcile, do not duplicate
List existing apps before creating one from automation. Update command, install command, or port on
the existing slug; use deletion only when the public identity should disappear. Name and icon
updates are metadata-only: they do not reinstall or restart the app, and sending the same icon path
again deliberately advances updatedAt so clients can refresh bytes replaced at that path. Public
visibility is a deliberate exposure boundary, not a health-check mechanism.
Runtime writes are complete only after Duet's computer accepts the workspace configuration. Apps report whether that reconciliation is pending, complete, or needs attention. A reconciliation failure is a structured API error: preserve the returned app, show the reason, and refresh the list instead of assuming the optimistic change became durable. Failed runtime edits retain the last accepted command, install command, and port while retaining name and icon changes from the request; failed deletes retain the app registration.
Shared apps arrive as replicas
Accepting a share whose folder registers apps materializes real app rows in the recipient
workspace, tagged with their origin (sourceShareId, sourceAppId) and with the access that share
grants (sourceShareMode). Its apiScopes declaration travels with the registration, but no key
does: the recipient workspace mints its own runtime credential. A replica is a real app on the
recipient's own computer at the recipient's own URL, so sharing an app is sharing files: a
write-mode recipient may change its runtime and publish their copy, and doing so never changes the
origin app's visibility. A read-mode
recipient may do neither. The recipient's own control is the disabled flag: disabling a replica is
durable — origin updates never resurrect it — and re-enabling is the same idempotent endpoint. A
replica records who disabled it and when, so the state is auditable. A replica is removed by
dropping the share, never by deleting the app.
Keep policy on the server
The apps scope permits access to this resource but does not replace workspace roles. Viewers can
list and inspect apps. Editors can register apps, change runtime configuration, make a public app
workspace-only, and delete it. Only owners can expose an app publicly.
Role alone cannot answer what a caller may do to a given app, because a replica lives in a
workspace the recipient owns while its permissions come from the share. Every app therefore carries
its own resolved controls (updateRuntime, makePublic, makePrivate, delete, manageDomain); the list-level
capabilities answers only the workspace-wide question of whether this caller may register an app.
Present controls from those values, and still handle authorization failures because roles and
shares can change after a client loads.
A custom domain changes the address, not admission
Each app can attach one hostname. Editors and owners can manage it, including for a disabled, broken, shared, or installed app; viewers can inspect its status and DNS instructions. A binding belongs to this local app and does not travel with shared files or marketplace content.
Attach returns the durable reservation while provider work proceeds. Repeating the same hostname
returns the same binding; another hostname on that app or a hostname already reserved elsewhere
returns a conflict. Follow the returned DNS instructions and conflicts. Duet checks automatically
while setup is pending; Recheck also requests a new check after DNS changes or retries an exhausted
removal. Only active bindings serve content or become standalone addresses. Provider failures
retain diagnostics so the user can repair setup and retry.
Full domain responses include checking: true while an active or failed binding has a queued
or running recheck. An active hostname keeps serving during the check. Observe the domain detail
or workspace collection until checking is absent and lastCheckedAt advances, then use the
returned status and diagnostics as the result. Initial setup still uses pending and verifying.
Removal stops custom-host serving immediately and cleans up the provider assignment in the
background. A removing binding keeps its reservation until cleanup finishes. When cleanup needs
attention, retryRequired identifies the manual retry; the existing Duet address continues to work.
The workspace collection uses the usual opaque continuation cursor and may return fewer rows than
the requested limit.
A provider write with an uncertain outcome requires operator repair. operatorRepairRequired
identifies this state; ordinary Recheck cannot clear it. The hostname stays reserved until support
confirms the remote work has settled and resumes cleanup. This prevents a delayed provider add or
delete from changing a later attachment.
Public custom-host content retains the app's indexing directives. Standard Duet addresses, private content, and platform authentication or error responses remain excluded from indexing.
A private app is reachable without being public
Visibility governs standalone access, not whether members can use the app. An anonymous browser opening a private app document can sign in through Duet and return to its original host and deep path. This works on its standard address and an active custom domain. API calls, iframe requests, and denied signed-in visitors receive the ordinary refusal instead of a sign-in redirect.
GET /v1/ws/{workspace}/apps/{slug}/launch mints the short-lived access grant after checking current
app access. Its optional host and path query parameters must be supplied together; the host must
be that app's standard address or current active custom domain. The path stays relative to that
host, and any old duet_access parameter is replaced. The default launch always uses the standard
Duet address. Embedded views use this host for both public and private apps, so customer DNS cannot
interrupt an embedded view. Standalone Open and Copy link actions use the active custom address
where offered; attaching never publishes the app.
Apps
14 operations /v1 /ws /{workspaceSlug} /app-domainsList current app domains in a workspace
- Scope
ws:{workspaceSlug}:apps- Request
- No JSON request body
- Query
Query parameters JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "cursor": { "type": "string", "minLength": 1 }, "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 } }, "additionalProperties": false }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "domain": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "appId": { "type": "string" }, "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] }, "records": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "domain": { "type": "string", "minLength": 1, "maxLength": 253 }, "value": { "type": "string", "minLength": 1 }, "reason": { "type": "string" } }, "required": [ "type", "domain", "value" ], "additionalProperties": false } }, "conflicts": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 253 }, "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "value": { "type": "string", "minLength": 1 } }, "required": [ "name", "type", "value" ], "additionalProperties": false } }, "lastError": { "type": "string", "maxLength": 2000 }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "lastCheckedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "verifiedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "retryRequired": { "type": "boolean" }, "operatorRepairRequired": { "type": "boolean", "const": true }, "checking": { "type": "boolean", "const": true } }, "required": [ "id", "workspaceId", "appId", "hostname", "status", "records", "conflicts", "createdAt", "updatedAt" ], "additionalProperties": false }, "app": { "type": "object", "properties": { "id": { "type": "string" }, "slug": { "type": "string" }, "name": { "type": "string" }, "controls": { "type": "object", "properties": { "manageDomain": { "type": "boolean" } }, "required": [ "manageDomain" ], "additionalProperties": false } }, "required": [ "id", "slug", "controls" ], "additionalProperties": false } }, "required": [ "domain", "app" ], "additionalProperties": false } }, "nextCursor": { "anyOf": [ { "type": "string", "minLength": 1 }, { "type": "null" } ] } }, "required": [ "items", "nextCursor" ], "additionalProperties": false }- Errors
Error body JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "type": "object", "properties": { "error": { "type": "string", "enum": [ "invalid_request", "invalid_cursor", "forbidden", "domain_occupied", "hostname_in_use", "domain_cleanup_pending", "domain_not_configured", "not_found" ] } }, "required": [ "error" ], "additionalProperties": false }, { "type": "object", "properties": { "error": { "type": "string", "const": "invalid_cursor" } }, "required": [ "error" ], "additionalProperties": false, "description": "Opaque collection cursor is malformed or bound to another walk (400)" } ] }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /ws /{workspaceSlug} /apps /{slug} /domainInspect an app domain and its DNS instructions
- Scope
ws:{workspaceSlug}:apps- Request
- No JSON request body
- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "domain": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "appId": { "type": "string" }, "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] }, "records": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "domain": { "type": "string", "minLength": 1, "maxLength": 253 }, "value": { "type": "string", "minLength": 1 }, "reason": { "type": "string" } }, "required": [ "type", "domain", "value" ], "additionalProperties": false } }, "conflicts": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 253 }, "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "value": { "type": "string", "minLength": 1 } }, "required": [ "name", "type", "value" ], "additionalProperties": false } }, "lastError": { "type": "string", "maxLength": 2000 }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "lastCheckedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "verifiedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "retryRequired": { "type": "boolean" }, "operatorRepairRequired": { "type": "boolean", "const": true }, "checking": { "type": "boolean", "const": true } }, "required": [ "id", "workspaceId", "appId", "hostname", "status", "records", "conflicts", "createdAt", "updatedAt" ], "additionalProperties": false }, { "type": "null" } ] } }, "required": [ "domain" ], "additionalProperties": false }- Errors
Error body JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "error": { "type": "string", "enum": [ "invalid_request", "invalid_cursor", "forbidden", "domain_occupied", "hostname_in_use", "domain_cleanup_pending", "domain_not_configured", "not_found" ] } }, "required": [ "error" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /ws /{workspaceSlug} /apps /{slug} /domainAttach one custom hostname without changing app visibility
- Scope
ws:{workspaceSlug}:apps- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "hostname": { "type": "string", "minLength": 1 } }, "required": [ "hostname" ], "additionalProperties": false }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "domain": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "appId": { "type": "string" }, "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] }, "records": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "domain": { "type": "string", "minLength": 1, "maxLength": 253 }, "value": { "type": "string", "minLength": 1 }, "reason": { "type": "string" } }, "required": [ "type", "domain", "value" ], "additionalProperties": false } }, "conflicts": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 253 }, "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "value": { "type": "string", "minLength": 1 } }, "required": [ "name", "type", "value" ], "additionalProperties": false } }, "lastError": { "type": "string", "maxLength": 2000 }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "lastCheckedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "verifiedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "retryRequired": { "type": "boolean" }, "operatorRepairRequired": { "type": "boolean", "const": true }, "checking": { "type": "boolean", "const": true } }, "required": [ "id", "workspaceId", "appId", "hostname", "status", "records", "conflicts", "createdAt", "updatedAt" ], "additionalProperties": false }, { "type": "null" } ] } }, "required": [ "domain" ], "additionalProperties": false }- Errors
Error body JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "error": { "type": "string", "enum": [ "invalid_request", "invalid_cursor", "forbidden", "domain_occupied", "hostname_in_use", "domain_cleanup_pending", "domain_not_configured", "not_found" ] } }, "required": [ "error" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Declared idempotent
/v1 /ws /{workspaceSlug} /apps /{slug} /domain /recheckRequest a fresh domain check or retry exhausted removal
- Scope
ws:{workspaceSlug}:apps- Request
- No request body
- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "domain": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "appId": { "type": "string" }, "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] }, "records": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "domain": { "type": "string", "minLength": 1, "maxLength": 253 }, "value": { "type": "string", "minLength": 1 }, "reason": { "type": "string" } }, "required": [ "type", "domain", "value" ], "additionalProperties": false } }, "conflicts": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 253 }, "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "value": { "type": "string", "minLength": 1 } }, "required": [ "name", "type", "value" ], "additionalProperties": false } }, "lastError": { "type": "string", "maxLength": 2000 }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "lastCheckedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "verifiedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "retryRequired": { "type": "boolean" }, "operatorRepairRequired": { "type": "boolean", "const": true }, "checking": { "type": "boolean", "const": true } }, "required": [ "id", "workspaceId", "appId", "hostname", "status", "records", "conflicts", "createdAt", "updatedAt" ], "additionalProperties": false }, { "type": "null" } ] } }, "required": [ "domain" ], "additionalProperties": false }- Errors
Error body JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "error": { "type": "string", "enum": [ "invalid_request", "invalid_cursor", "forbidden", "domain_occupied", "hostname_in_use", "domain_cleanup_pending", "domain_not_configured", "not_found" ] } }, "required": [ "error" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /ws /{workspaceSlug} /apps /{slug} /domainStop serving a custom hostname and schedule provider cleanup
- Scope
ws:{workspaceSlug}:apps- Request
- No JSON request body
- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "domain": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "appId": { "type": "string" }, "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] }, "records": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "domain": { "type": "string", "minLength": 1, "maxLength": 253 }, "value": { "type": "string", "minLength": 1 }, "reason": { "type": "string" } }, "required": [ "type", "domain", "value" ], "additionalProperties": false } }, "conflicts": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 253 }, "type": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^[\\x20-\\x7e]+$" }, "value": { "type": "string", "minLength": 1 } }, "required": [ "name", "type", "value" ], "additionalProperties": false } }, "lastError": { "type": "string", "maxLength": 2000 }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "lastCheckedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "verifiedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "retryRequired": { "type": "boolean" }, "operatorRepairRequired": { "type": "boolean", "const": true }, "checking": { "type": "boolean", "const": true } }, "required": [ "id", "workspaceId", "appId", "hostname", "status", "records", "conflicts", "createdAt", "updatedAt" ], "additionalProperties": false }, { "type": "null" } ] } }, "required": [ "domain" ], "additionalProperties": false }- Errors
Error body JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "error": { "type": "string", "enum": [ "invalid_request", "invalid_cursor", "forbidden", "domain_occupied", "hostname_in_use", "domain_cleanup_pending", "domain_not_configured", "not_found" ] } }, "required": [ "error" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Declared idempotent
/v1 /ws /{workspaceSlug} /appsList workspace apps, optionally filtered by exact id, the deepest app containing a cwd, or drive path
- Scope
ws:{workspaceSlug}:apps- Request
- No JSON request body
- Query
Query parameters JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "cursor": { "type": "string", "minLength": 1 }, "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "id": { "type": "string", "minLength": 1 }, "cwd": { "type": "string", "minLength": 1, "maxLength": 1024, "pattern": "^[^\\u0000-\\u001f\\u007f]+$" }, "path": { "type": "string" }, "scope": { "type": "string", "enum": [ "subtree", "children", "self" ] } }, "additionalProperties": false }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "anchorId": { "type": "string" }, "anchorPath": { "type": "string" }, "anchorState": { "type": "string", "enum": [ "active", "broken", "orphaned" ] }, "command": { "type": "string", "minLength": 1 }, "apiScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members" ] } }, "installCommand": { "type": "string", "minLength": 1 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "slug": { "type": "string" }, "name": { "type": "string" }, "icon": { "type": "string" }, "visibility": { "type": "string", "enum": [ "folder", "public" ] }, "canonicalUrl": { "type": "string" }, "customDomain": { "type": "object", "properties": { "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] } }, "required": [ "hostname", "status" ], "additionalProperties": false }, "runtimeStatus": { "type": "string", "enum": [ "reconciling", "reconciled", "reconcile_failed" ] }, "reconciliationError": { "type": "string", "minLength": 1, "maxLength": 2000 }, "sourceShareId": { "type": "string" }, "sourceShareMode": { "type": "string", "enum": [ "read", "write" ] }, "sourceAppId": { "type": "string" }, "listingSubscriptionId": { "type": "string" }, "disabledAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "disabledByUserId": { "type": "string" }, "createdByUserId": { "type": "string" }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "controls": { "type": "object", "properties": { "manageDomain": { "type": "boolean" }, "updateRuntime": { "type": "boolean" }, "makePublic": { "type": "boolean" }, "makePrivate": { "type": "boolean" }, "delete": { "type": "boolean" } }, "required": [ "manageDomain", "updateRuntime", "makePublic", "makePrivate", "delete" ], "additionalProperties": false } }, "required": [ "id", "workspaceId", "anchorId", "anchorPath", "anchorState", "command", "apiScopes", "port", "slug", "visibility", "canonicalUrl", "runtimeStatus", "createdByUserId", "createdAt", "updatedAt", "controls" ], "additionalProperties": false } }, "nextCursor": { "anyOf": [ { "type": "string", "minLength": 1 }, { "type": "null" } ] }, "meta": { "type": "object", "properties": { "capabilities": { "type": "object", "properties": { "register": { "type": "boolean" } }, "required": [ "register" ], "additionalProperties": false } }, "required": [ "capabilities" ], "additionalProperties": false } }, "required": [ "items", "nextCursor" ], "additionalProperties": false }- Errors
Opaque collection cursor is malformed or bound to another walk (400)
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "error": { "type": "string", "const": "invalid_cursor" } }, "required": [ "error" ], "additionalProperties": false, "description": "Opaque collection cursor is malformed or bound to another walk (400)" }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /ws /{workspaceSlug} /apps /{slug} /launchOpen an app through a short-lived access grant, optionally returning to its validated host and path
- Scope
ws:{workspaceSlug}:apps- Request
- No JSON request body
- Query
Query parameters JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "host": { "type": "string" }, "path": { "type": "string" } }, "additionalProperties": false }- Response
- No structured response body
- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /ws /{workspaceSlug} /appsRegister a workspace folder as an app runtime with optional display metadata
- Scope
ws:{workspaceSlug}:apps- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "path": { "type": "string", "minLength": 1 }, "command": { "type": "string" }, "apiScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members" ] } }, "installCommand": { "type": "string" }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "slug": { "type": "string" }, "name": { "type": "string", "minLength": 1, "maxLength": 64 }, "icon": { "type": "string" } }, "required": [ "path", "command", "apiScopes", "slug" ] }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "app": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "anchorId": { "type": "string" }, "anchorPath": { "type": "string" }, "anchorState": { "type": "string", "enum": [ "active", "broken", "orphaned" ] }, "command": { "type": "string", "minLength": 1 }, "apiScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members" ] } }, "installCommand": { "type": "string", "minLength": 1 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "slug": { "type": "string" }, "name": { "type": "string" }, "icon": { "type": "string" }, "visibility": { "type": "string", "enum": [ "folder", "public" ] }, "canonicalUrl": { "type": "string" }, "customDomain": { "type": "object", "properties": { "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] } }, "required": [ "hostname", "status" ], "additionalProperties": false }, "runtimeStatus": { "type": "string", "enum": [ "reconciling", "reconciled", "reconcile_failed" ] }, "reconciliationError": { "type": "string", "minLength": 1, "maxLength": 2000 }, "sourceShareId": { "type": "string" }, "sourceShareMode": { "type": "string", "enum": [ "read", "write" ] }, "sourceAppId": { "type": "string" }, "listingSubscriptionId": { "type": "string" }, "disabledAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "disabledByUserId": { "type": "string" }, "createdByUserId": { "type": "string" }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "controls": { "type": "object", "properties": { "manageDomain": { "type": "boolean" }, "updateRuntime": { "type": "boolean" }, "makePublic": { "type": "boolean" }, "makePrivate": { "type": "boolean" }, "delete": { "type": "boolean" } }, "required": [ "manageDomain", "updateRuntime", "makePublic", "makePrivate", "delete" ], "additionalProperties": false } }, "required": [ "id", "workspaceId", "anchorId", "anchorPath", "anchorState", "command", "apiScopes", "port", "slug", "visibility", "canonicalUrl", "runtimeStatus", "createdByUserId", "createdAt", "updatedAt", "controls" ], "additionalProperties": false } }, "required": [ "app" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /ws /{workspaceSlug} /apps /{appSlug}Get one registered app by slug
- Scope
ws:{workspaceSlug}:apps- Request
- No JSON request body
- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "app": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "anchorId": { "type": "string" }, "anchorPath": { "type": "string" }, "anchorState": { "type": "string", "enum": [ "active", "broken", "orphaned" ] }, "command": { "type": "string", "minLength": 1 }, "apiScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members" ] } }, "installCommand": { "type": "string", "minLength": 1 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "slug": { "type": "string" }, "name": { "type": "string" }, "icon": { "type": "string" }, "visibility": { "type": "string", "enum": [ "folder", "public" ] }, "canonicalUrl": { "type": "string" }, "customDomain": { "type": "object", "properties": { "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] } }, "required": [ "hostname", "status" ], "additionalProperties": false }, "runtimeStatus": { "type": "string", "enum": [ "reconciling", "reconciled", "reconcile_failed" ] }, "reconciliationError": { "type": "string", "minLength": 1, "maxLength": 2000 }, "sourceShareId": { "type": "string" }, "sourceShareMode": { "type": "string", "enum": [ "read", "write" ] }, "sourceAppId": { "type": "string" }, "listingSubscriptionId": { "type": "string" }, "disabledAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "disabledByUserId": { "type": "string" }, "createdByUserId": { "type": "string" }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "controls": { "type": "object", "properties": { "manageDomain": { "type": "boolean" }, "updateRuntime": { "type": "boolean" }, "makePublic": { "type": "boolean" }, "makePrivate": { "type": "boolean" }, "delete": { "type": "boolean" } }, "required": [ "manageDomain", "updateRuntime", "makePublic", "makePrivate", "delete" ], "additionalProperties": false } }, "required": [ "id", "workspaceId", "anchorId", "anchorPath", "anchorState", "command", "apiScopes", "port", "slug", "visibility", "canonicalUrl", "runtimeStatus", "createdByUserId", "createdAt", "updatedAt", "controls" ], "additionalProperties": false } }, "required": [ "app" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /ws /{workspaceSlug} /apps /{appSlug}Update app display metadata or reconcile changed runtime settings
- Scope
ws:{workspaceSlug}:apps- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "command": { "type": "string" }, "apiScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members" ] } }, "installCommand": { "type": "string" }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "name": { "type": "string", "minLength": 1, "maxLength": 64 }, "icon": { "type": "string" } } }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "app": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "anchorId": { "type": "string" }, "anchorPath": { "type": "string" }, "anchorState": { "type": "string", "enum": [ "active", "broken", "orphaned" ] }, "command": { "type": "string", "minLength": 1 }, "apiScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members" ] } }, "installCommand": { "type": "string", "minLength": 1 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "slug": { "type": "string" }, "name": { "type": "string" }, "icon": { "type": "string" }, "visibility": { "type": "string", "enum": [ "folder", "public" ] }, "canonicalUrl": { "type": "string" }, "customDomain": { "type": "object", "properties": { "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] } }, "required": [ "hostname", "status" ], "additionalProperties": false }, "runtimeStatus": { "type": "string", "enum": [ "reconciling", "reconciled", "reconcile_failed" ] }, "reconciliationError": { "type": "string", "minLength": 1, "maxLength": 2000 }, "sourceShareId": { "type": "string" }, "sourceShareMode": { "type": "string", "enum": [ "read", "write" ] }, "sourceAppId": { "type": "string" }, "listingSubscriptionId": { "type": "string" }, "disabledAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "disabledByUserId": { "type": "string" }, "createdByUserId": { "type": "string" }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "controls": { "type": "object", "properties": { "manageDomain": { "type": "boolean" }, "updateRuntime": { "type": "boolean" }, "makePublic": { "type": "boolean" }, "makePrivate": { "type": "boolean" }, "delete": { "type": "boolean" } }, "required": [ "manageDomain", "updateRuntime", "makePublic", "makePrivate", "delete" ], "additionalProperties": false } }, "required": [ "id", "workspaceId", "anchorId", "anchorPath", "anchorState", "command", "apiScopes", "port", "slug", "visibility", "canonicalUrl", "runtimeStatus", "createdByUserId", "createdAt", "updatedAt", "controls" ], "additionalProperties": false } }, "required": [ "app" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /ws /{workspaceSlug} /apps /{appSlug} /reanchorRepair a broken app anchor by slug after the automatic move rail cannot recover its folder
- Scope
ws:{workspaceSlug}:apps- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "path": { "type": "string" } }, "required": [ "path" ] }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "app": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "anchorId": { "type": "string" }, "anchorPath": { "type": "string" }, "anchorState": { "type": "string", "enum": [ "active", "broken", "orphaned" ] }, "command": { "type": "string", "minLength": 1 }, "apiScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members" ] } }, "installCommand": { "type": "string", "minLength": 1 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "slug": { "type": "string" }, "name": { "type": "string" }, "icon": { "type": "string" }, "visibility": { "type": "string", "enum": [ "folder", "public" ] }, "canonicalUrl": { "type": "string" }, "customDomain": { "type": "object", "properties": { "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] } }, "required": [ "hostname", "status" ], "additionalProperties": false }, "runtimeStatus": { "type": "string", "enum": [ "reconciling", "reconciled", "reconcile_failed" ] }, "reconciliationError": { "type": "string", "minLength": 1, "maxLength": 2000 }, "sourceShareId": { "type": "string" }, "sourceShareMode": { "type": "string", "enum": [ "read", "write" ] }, "sourceAppId": { "type": "string" }, "listingSubscriptionId": { "type": "string" }, "disabledAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "disabledByUserId": { "type": "string" }, "createdByUserId": { "type": "string" }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "controls": { "type": "object", "properties": { "manageDomain": { "type": "boolean" }, "updateRuntime": { "type": "boolean" }, "makePublic": { "type": "boolean" }, "makePrivate": { "type": "boolean" }, "delete": { "type": "boolean" } }, "required": [ "manageDomain", "updateRuntime", "makePublic", "makePrivate", "delete" ], "additionalProperties": false } }, "required": [ "id", "workspaceId", "anchorId", "anchorPath", "anchorState", "command", "apiScopes", "port", "slug", "visibility", "canonicalUrl", "runtimeStatus", "createdByUserId", "createdAt", "updatedAt", "controls" ], "additionalProperties": false } }, "required": [ "app" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Not declared idempotent
/v1 /ws /{workspaceSlug} /apps /{appSlug} /visibilityMake an app workspace-only or public
- Scope
ws:{workspaceSlug}:apps- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "visibility": { "type": "string", "enum": [ "folder", "public" ] } }, "required": [ "visibility" ] }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "app": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "anchorId": { "type": "string" }, "anchorPath": { "type": "string" }, "anchorState": { "type": "string", "enum": [ "active", "broken", "orphaned" ] }, "command": { "type": "string", "minLength": 1 }, "apiScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members" ] } }, "installCommand": { "type": "string", "minLength": 1 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "slug": { "type": "string" }, "name": { "type": "string" }, "icon": { "type": "string" }, "visibility": { "type": "string", "enum": [ "folder", "public" ] }, "canonicalUrl": { "type": "string" }, "customDomain": { "type": "object", "properties": { "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] } }, "required": [ "hostname", "status" ], "additionalProperties": false }, "runtimeStatus": { "type": "string", "enum": [ "reconciling", "reconciled", "reconcile_failed" ] }, "reconciliationError": { "type": "string", "minLength": 1, "maxLength": 2000 }, "sourceShareId": { "type": "string" }, "sourceShareMode": { "type": "string", "enum": [ "read", "write" ] }, "sourceAppId": { "type": "string" }, "listingSubscriptionId": { "type": "string" }, "disabledAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "disabledByUserId": { "type": "string" }, "createdByUserId": { "type": "string" }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "controls": { "type": "object", "properties": { "manageDomain": { "type": "boolean" }, "updateRuntime": { "type": "boolean" }, "makePublic": { "type": "boolean" }, "makePrivate": { "type": "boolean" }, "delete": { "type": "boolean" } }, "required": [ "manageDomain", "updateRuntime", "makePublic", "makePrivate", "delete" ], "additionalProperties": false } }, "required": [ "id", "workspaceId", "anchorId", "anchorPath", "anchorState", "command", "apiScopes", "port", "slug", "visibility", "canonicalUrl", "runtimeStatus", "createdByUserId", "createdAt", "updatedAt", "controls" ], "additionalProperties": false } }, "required": [ "app" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Declared idempotent
/v1 /ws /{workspaceSlug} /apps /{appSlug} /disabledDisable or re-enable a shared app replica
- Scope
ws:{workspaceSlug}:apps- Request
Request JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "disabled": { "type": "boolean" } }, "required": [ "disabled" ] }- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "app": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "anchorId": { "type": "string" }, "anchorPath": { "type": "string" }, "anchorState": { "type": "string", "enum": [ "active", "broken", "orphaned" ] }, "command": { "type": "string", "minLength": 1 }, "apiScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "enum": [ "files:read", "files:write", "memory", "sessions", "agents", "services", "integrations", "apps", "share", "publish", "members" ] } }, "installCommand": { "type": "string", "minLength": 1 }, "port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "slug": { "type": "string" }, "name": { "type": "string" }, "icon": { "type": "string" }, "visibility": { "type": "string", "enum": [ "folder", "public" ] }, "canonicalUrl": { "type": "string" }, "customDomain": { "type": "object", "properties": { "hostname": { "type": "string", "pattern": "^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$" }, "status": { "type": "string", "enum": [ "pending", "verifying", "active", "failed", "removing" ] } }, "required": [ "hostname", "status" ], "additionalProperties": false }, "runtimeStatus": { "type": "string", "enum": [ "reconciling", "reconciled", "reconcile_failed" ] }, "reconciliationError": { "type": "string", "minLength": 1, "maxLength": 2000 }, "sourceShareId": { "type": "string" }, "sourceShareMode": { "type": "string", "enum": [ "read", "write" ] }, "sourceAppId": { "type": "string" }, "listingSubscriptionId": { "type": "string" }, "disabledAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "disabledByUserId": { "type": "string" }, "createdByUserId": { "type": "string" }, "createdAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "controls": { "type": "object", "properties": { "manageDomain": { "type": "boolean" }, "updateRuntime": { "type": "boolean" }, "makePublic": { "type": "boolean" }, "makePrivate": { "type": "boolean" }, "delete": { "type": "boolean" } }, "required": [ "manageDomain", "updateRuntime", "makePublic", "makePrivate", "delete" ], "additionalProperties": false } }, "required": [ "id", "workspaceId", "anchorId", "anchorPath", "anchorState", "command", "apiScopes", "port", "slug", "visibility", "canonicalUrl", "runtimeStatus", "createdByUserId", "createdAt", "updatedAt", "controls" ], "additionalProperties": false } }, "required": [ "app" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Declared idempotent
/v1 /ws /{workspaceSlug} /apps /{appSlug}Stop serving and unregister an app
- Scope
ws:{workspaceSlug}:apps- Request
- No JSON request body
- Response
Response JSON schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "ok": { "type": "boolean", "const": true } }, "required": [ "ok" ], "additionalProperties": false }- Delivery
- Standard response
- Retry
- Declared idempotent