SandboxREST APIFleets, templates, secrets and teams routes

Fleets, templates, secrets and teams routes

Manage fleets of sandboxes and the resources sandboxes start from or share: templates, images, instances, secrets, SSH keys, startup scripts, lines and teams.

Every route is on https://sandbox.tangle.tools and takes your account API key as Authorization: Bearer <key> unless it says otherwise. Errors use the shape in Error codes. This page is generated from the OpenAPI document, which also has every response schema.

Fleets

RouteDoes
GET /v1/fleetsList sandbox fleets
POST /v1/fleetsCreate a sandbox fleet record
GET /v1/fleets/capabilitiesList fleet driver capabilities
POST /v1/fleets/estimateEstimate sandbox fleet cost before create
GET /v1/fleets/operationsSummarize fleet operational risk for the current owner
POST /v1/fleets/reap-expiredDelete expired sandbox fleets for the current owner
POST /v1/fleets/reconcileFind fleet machine records whose sandbox no longer exists
GET /v1/fleets/{fleetId}Get a sandbox fleet
DELETE /v1/fleets/{fleetId}Delete a sandbox fleet record
GET /v1/fleets/{fleetId}/costEstimate current sandbox fleet cost
POST /v1/fleets/{fleetId}/dispatchDispatch a command to fleet machines
POST /v1/fleets/{fleetId}/dispatch/streamStream a command dispatch to fleet machines
POST /v1/fleets/{fleetId}/dispatch/{dispatchId}/cancelCancel queued fleet dispatch branches
GET /v1/fleets/{fleetId}/dispatch/{dispatchId}/resultsRead buffered fleet dispatch results
POST /v1/fleets/{fleetId}/machinesAdd a machine to a sandbox fleet record
DELETE /v1/fleets/{fleetId}/machines/{machineId}Remove a machine from a sandbox fleet record
GET /v1/fleets/{fleetId}/manifestGet a fleet manifest for coordinator workflows
POST /v1/fleets/{fleetId}/tokenMint a fleet-scoped agent token
GET /v1/fleets/{fleetId}/traceExport fleet trace and intelligence envelope
GET /v1/fleets/{fleetId}/usageGet fleet usage and intelligence summary
POST /v1/fleets/{fleetId}/workspace/reconcileCheck fleet machines against the shared workspace mount
POST /v1/fleets/{fleetId}/workspace/snapshotsSnapshot the fleet workspace
POST /v1/fleets/{fleetId}/workspace/snapshots/{snapshotId}/restoreRestore the fleet workspace from a snapshot

List sandbox fleets

GET /v1/fleets

StatusMeaning
200Fleets
500Internal error

Create a sandbox fleet record

POST /v1/fleets

Request body (application/json):

FieldTypeRequiredDescription
idstringYes
status”creating” | “running”No
metadataobjectNo
workspaceobjectNo
policyobjectNo
resourcesobjectNo
maxConcurrentCreatesintegerNo
parentobjectNo
machinesarray of objectYes
StatusMeaning
201Fleet created
400Validation error
403Forbidden
409Conflict
500Internal error
502Sandbox service verification failed

List fleet driver capabilities

GET /v1/fleets/capabilities

StatusMeaning
200Fleet driver capabilities

Estimate sandbox fleet cost before create

POST /v1/fleets/estimate

Request body (application/json):

FieldTypeRequiredDescription
machineCountintegerYes
policyobjectNo
resourcesobjectNo
maxConcurrentCreatesintegerNo
StatusMeaning
200Fleet cost estimate
400Validation error
500Internal error

Summarize fleet operational risk for the current owner

GET /v1/fleets/operations

StatusMeaning
200Fleet operations summary
500Internal error

Delete expired sandbox fleets for the current owner

POST /v1/fleets/reap-expired

Request body (application/json):

FieldTypeRequiredDescription
dryRunbooleanNo
StatusMeaning
200Expired fleet cleanup results
500Internal error

Find fleet machine records whose sandbox no longer exists

POST /v1/fleets/reconcile

Request body (application/json):

FieldTypeRequiredDescription
dryRunbooleanNo
StatusMeaning
200Fleet reconciliation result
500Internal error

Get a sandbox fleet

GET /v1/fleets/{fleetId}

ParameterInRequiredTypeDescription
fleetIdpathYesstring
StatusMeaning
200Fleet
400Bad request
404Not found
500Internal error

Delete a sandbox fleet record

DELETE /v1/fleets/{fleetId}

ParameterInRequiredTypeDescription
fleetIdpathYesstring
StatusMeaning
200Fleet deleted
500Internal error
502Fleet machine deprovision failed

Estimate current sandbox fleet cost

GET /v1/fleets/{fleetId}/cost

ParameterInRequiredTypeDescription
fleetIdpathYesstring
StatusMeaning
200Fleet cost estimate
404Not found
500Internal error

Dispatch a command to fleet machines

POST /v1/fleets/{fleetId}/dispatch

ParameterInRequiredTypeDescription
fleetIdpathYesstring

Request body (application/json): one of 2 shapes; see the OpenAPI document.

StatusMeaning
200Dispatch results
400Bad request
403PROFILE_SECRET_ISOLATION_UNAVAILABLE: backend.metadata.profileSecretIsolation needs every selected machine’s runtime to seal the secret launch
404Not found
409Dispatch conflict
500Internal error
503PROFILE_SECRET_ISOLATION_UNAVAILABLE with reason sidecar_unreachable: a selected machine’s runtime could not be asked; retry after Retry-After

Stream a command dispatch to fleet machines

POST /v1/fleets/{fleetId}/dispatch/stream

Takes the same body as POST /v1/fleets/{fleetId}/dispatch and answers as server-sent events while the machines run. Each machine emits fleet.dispatch.branch.started and fleet.dispatch.branch.finished. The stream ends with fleet.dispatch.finished or fleet.dispatch.error. A failure before the stream starts is a JSON error instead. A dropped connection cancels the machines that have not started.

ParameterInRequiredTypeDescription
fleetIdpathYesstring

Request body (application/json): one of 2 shapes; see the OpenAPI document.

StatusMeaning
200Server-sent events (text/event-stream). Each frame has an event name and a JSON data field, modeled by the schema.
400Invalid fleet ID or dispatch body (VALIDATION_ERROR)
402The account that pays for the fleet has recorded debt (INSUFFICIENT_BALANCE)
403The fleet token is not scoped to this fleet or lacks the exec or prompt action, or the backend’s profile secret isolation is unavailable (FORBIDDEN, PROFILE_SECRET_ISOLATION_UNAVAILABLE)
404Fleet not found (NOT_FOUND)
409A dispatch with this dispatchId is already active (CONFLICT)
429The paying account’s balance is below the admission floor (QUOTA_EXCEEDED)
503A selected machine could not be asked to prove secret isolation; retry after Retry-After (PROFILE_SECRET_ISOLATION_UNAVAILABLE)

Cancel queued fleet dispatch branches

POST /v1/fleets/{fleetId}/dispatch/{dispatchId}/cancel

ParameterInRequiredTypeDescription
fleetIdpathYesstring
dispatchIdpathYesstring
StatusMeaning
202Dispatch cancel requested
403Forbidden
404Not found
500Internal error

Read buffered fleet dispatch results

GET /v1/fleets/{fleetId}/dispatch/{dispatchId}/results

ParameterInRequiredTypeDescription
fleetIdpathYesstring
dispatchIdpathYesstring
cursorqueryNostring
limitqueryNostring
machinequeryNostring or array of string
StatusMeaning
200Buffered dispatch results
404Not found
500Internal error

Add a machine to a sandbox fleet record

POST /v1/fleets/{fleetId}/machines

ParameterInRequiredTypeDescription
fleetIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
machineIdstringYes
sandboxIdstringYes
status”creating” | “running” | “degraded” | “deleting” | “deleted” | “failed”No
role”coordinator” | “worker”No
driverType”docker” | “firecracker” | “host-agent” | “tangle”No
environmentstringNo
templateIdstringNo
publicTemplateIdstringNo
acceleratorCountintegerNo
driverTimingsobjectNo
StatusMeaning
201Machine added
400Validation error
403Forbidden
404Not found
409Conflict
500Internal error
502Sandbox service verification failed

Remove a machine from a sandbox fleet record

DELETE /v1/fleets/{fleetId}/machines/{machineId}

ParameterInRequiredTypeDescription
fleetIdpathYesstring
machineIdpathYesstring
StatusMeaning
200Machine removed
404Not found
500Internal error
502Fleet machine deprovision failed

Get a fleet manifest for coordinator workflows

GET /v1/fleets/{fleetId}/manifest

ParameterInRequiredTypeDescription
fleetIdpathYesstring
StatusMeaning
200Fleet manifest
404Not found
500Internal error

Mint a fleet-scoped agent token

POST /v1/fleets/{fleetId}/token

ParameterInRequiredTypeDescription
fleetIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
actionsarray of “list” | “create” | “delete” | “exec” | “prompt” | “read” | “write”No
policyobjectNo
ttlMinutesintegerNo
StatusMeaning
200Fleet-scoped token
403Forbidden
404Not found
409Fleet expired
500Internal error

Export fleet trace and intelligence envelope

GET /v1/fleets/{fleetId}/trace

ParameterInRequiredTypeDescription
fleetIdpathYesstring
includeIntelligencequeryNo”true” | “false”
StatusMeaning
200Fleet trace export
404Not found
500Internal error

Get fleet usage and intelligence summary

GET /v1/fleets/{fleetId}/usage

ParameterInRequiredTypeDescription
fleetIdpathYesstring
StatusMeaning
200Fleet usage summary
404Not found
500Internal error

Check fleet machines against the shared workspace mount

POST /v1/fleets/{fleetId}/workspace/reconcile

Compares each machine’s recorded workspace mount path with the fleet’s shared workspace mount path. It reads recorded state, contacts no machine and changes nothing. A fleet with no shared workspace mount path reports every machine as mounted. A fleet token needs the read action.

ParameterInRequiredTypeDescription
fleetIdpathYesstring
StatusMeaning
200Mount check
400Invalid fleet ID (VALIDATION_ERROR)
403The fleet token is not scoped to this fleet or lacks the action (FORBIDDEN), or the credential is restricted to its sandbox
404Fleet not found (NOT_FOUND)

Snapshot the fleet workspace

POST /v1/fleets/{fleetId}/workspace/snapshots

Acts on the workspace of the fleet’s coordinator machine, or of its first machine when none is a coordinator. A fleet token needs the read action.

ParameterInRequiredTypeDescription
fleetIdpathYesstring
StatusMeaning
200Snapshot captured
400Invalid fleet or snapshot ID, or the sandbox service refused the request (VALIDATION_ERROR)
403The fleet token is not scoped to this fleet or lacks the action (FORBIDDEN), or the credential is restricted to its sandbox
404Fleet not found, the fleet has no machines, or the sandbox service found no such sandbox or snapshot (NOT_FOUND)
409The sandbox service reported a conflict (CONFLICT)
429The sandbox service rate-limited or refused the request for quota (RATE_LIMITED, QUOTA_EXCEEDED)
502The sandbox service failed (UPSTREAM_ERROR)

Restore the fleet workspace from a snapshot

POST /v1/fleets/{fleetId}/workspace/snapshots/{snapshotId}/restore

Acts on the workspace of the fleet’s coordinator machine, or of its first machine when none is a coordinator. A fleet token needs the write action.

ParameterInRequiredTypeDescription
fleetIdpathYesstring
snapshotIdpathYesstring
StatusMeaning
200Snapshot restored
202Restore accepted; it runs as a background job
400Invalid fleet or snapshot ID, or the sandbox service refused the request (VALIDATION_ERROR)
403The fleet token is not scoped to this fleet or lacks the action (FORBIDDEN), or the credential is restricted to its sandbox
404Fleet not found, the fleet has no machines, or the sandbox service found no such sandbox or snapshot (NOT_FOUND)
409The sandbox service reported a conflict (CONFLICT)
429The sandbox service rate-limited or refused the request for quota (RATE_LIMITED, QUOTA_EXCEEDED)
502The sandbox service failed (UPSTREAM_ERROR)

Templates

RouteDoes
GET /v1/environmentsList environments
GET /v1/templatesList user templates
POST /v1/templatesCreate a template from a snapshot
DELETE /v1/templates/{id}Delete a template

List environments

GET /v1/environments

The credential is optional. Without one, the list holds the system environments. With one, it also holds the caller’s templates; a failed template lookup leaves them out without an error.

Authentication: an API key as a bearer token, optional.

StatusMeaning
200Environments a sandbox can start from

List user templates

GET /v1/templates

StatusMeaning
200List of templates
500Internal error

Create a template from a snapshot

POST /v1/templates

Request body (application/json):

FieldTypeRequiredDescription
namestringYes
descriptionstringNo
snapshotIdstringYes
sourceSandboxIdstringYes
environmentstringNo
configobjectNo
StatusMeaning
201Template created
400Validation error
409Template already exists
500Internal error

Delete a template

DELETE /v1/templates/{id}

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Template deleted
404Not found
500Internal error

Public templates

RouteDoes
POST /v1/public-templatesPublish a snapshot as a public template
GET /v1/public-templatesSearch public templates
GET /v1/public-templates/artifacts/{artifactId}Get public template publish artifact status
GET /v1/public-templates/featuredList featured public templates
GET /v1/public-templates/publish-jobs/{jobId}Get public template publish job status
GET /v1/public-templates/{id}Get a public template
GET /v1/public-templates/{id}/versionsList versions for a public template
POST /v1/public-templates/{id}/versionsPublish a new version for a public template

Publish a snapshot as a public template

POST /v1/public-templates

Request body (application/json):

FieldTypeRequiredDescription
namestringYes
slugstringNo
descriptionstringNo
websiteUrlstringNo
snapshotIdstringYes
sourceSandboxIdstringYes
teamIdstringNo
readmeMarkdownstringNo
tagsarray of stringNo
releaseNotesstringNo
forkedFromTemplateIdstringNo
StatusMeaning
202Publish queued
400Validation error
403Forbidden
404Snapshot not found
409Conflict
500Internal error

Search public templates

GET /v1/public-templates

ParameterInRequiredTypeDescription
qqueryNostring
tagqueryNostring
featuredqueryNoboolean or null
limitqueryNointeger
offsetqueryNointeger or null
StatusMeaning
200Templates

Get public template publish artifact status

GET /v1/public-templates/artifacts/{artifactId}

ParameterInRequiredTypeDescription
artifactIdpathYesstring
StatusMeaning
200Artifact
403Forbidden
404Not found
500Internal server error

GET /v1/public-templates/featured

StatusMeaning
200Templates

Get public template publish job status

GET /v1/public-templates/publish-jobs/{jobId}

ParameterInRequiredTypeDescription
jobIdpathYesstring
StatusMeaning
200Publish job
403Forbidden
404Not found
500Internal server error

Get a public template

GET /v1/public-templates/{id}

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Template
404Not found
500Internal error

List versions for a public template

GET /v1/public-templates/{id}/versions

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Versions
404Not found
500Internal error

Publish a new version for a public template

POST /v1/public-templates/{id}/versions

ParameterInRequiredTypeDescription
idpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
snapshotIdstringYes
sourceSandboxIdstringYes
readmeMarkdownstringNo
tagsarray of stringNo
releaseNotesstringNo
StatusMeaning
202Version publish queued
400Validation error
403Forbidden
404Not found
500Internal error

Images

RouteDoes
POST /v1/imagesBuild an image
GET /v1/imagesList images
GET /v1/images/{id}Get an image
DELETE /v1/images/{id}Delete an image
POST /v1/images/{id}/tagTag an image

Build an image

POST /v1/images

Image builds are disabled. Every request is refused before its body is read.

StatusMeaning
401Missing or invalid credential
403Image builds are disabled (IMAGE_BUILDS_DISABLED), or the credential is restricted to its own sandbox
503The image catalog did not answer; retry shortly

List images

GET /v1/images

Image builds are disabled, so the list is empty.

ParameterInRequiredTypeDescription
limitqueryNonumber
offsetqueryNonumber or null
labelqueryNostring
includeCachequeryNoboolean or null
StatusMeaning
200The images
401Missing or invalid credential
403The credential is restricted to its own sandbox (SANDBOX_KEY_RESOURCE_FORBIDDEN)
503The image catalog did not answer; retry shortly

Get an image

GET /v1/images/{id}

Image builds are disabled, so no image exists to read, delete or tag: every id answers 404.

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
401Missing or invalid credential
403The credential is restricted to its own sandbox (SANDBOX_KEY_RESOURCE_FORBIDDEN)
404No image has this id (NOT_FOUND)
503The image catalog did not answer; retry shortly

Delete an image

DELETE /v1/images/{id}

Image builds are disabled, so no image exists to read, delete or tag: every id answers 404.

ParameterInRequiredTypeDescription
idpathYesstring
forcequeryNoboolean or null
StatusMeaning
401Missing or invalid credential
403The credential is restricted to its own sandbox (SANDBOX_KEY_RESOURCE_FORBIDDEN)
404No image has this id (NOT_FOUND)
503The image catalog did not answer; retry shortly

Tag an image

POST /v1/images/{id}/tag

Image builds are disabled, so no image exists to read, delete or tag: every id answers 404.

ParameterInRequiredTypeDescription
idpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
tagstringYes
StatusMeaning
401Missing or invalid credential
403The credential is restricted to its own sandbox (SANDBOX_KEY_RESOURCE_FORBIDDEN)
404No image has this id (NOT_FOUND)
503The image catalog did not answer; retry shortly

Instances

RouteDoes
GET /v1/instances/{key}Get an instance
PATCH /v1/instances/{key}Update an instance
DELETE /v1/instances/{key}Release an instance key
PUT /v1/instances/{key}/bindingBind a sandbox to an instance
POST /v1/instances/{key}/replaceReplace an instance’s sandbox

Get an instance

GET /v1/instances/{key}

An instance maps a key you choose to the sandbox that serves it now. Keys are scoped to the authenticated customer.

ParameterInRequiredTypeDescription
keypathYesstring1-200 characters: letters, digits and . _ : @ -, starting with a letter or digit.
StatusMeaning
200The instance record
400The key or the body is invalid (INVALID_INSTANCE_KEY, VALIDATION_ERROR)
401Missing or invalid credential
403The credential is restricted to its own sandbox (SANDBOX_KEY_RESOURCE_FORBIDDEN)
404The key has no record (INSTANCE_NOT_FOUND)

Update an instance

PATCH /v1/instances/{key}

Changes the profile version that new sessions bind to, or marks or clears a failed start, on the sandbox of the given generation. A marked failed start keeps its first time. Send at least one of profileVersion and unstartable.

ParameterInRequiredTypeDescription
keypathYesstring1-200 characters: letters, digits and . _ : @ -, starting with a letter or digit.

Request body (application/json):

FieldTypeRequiredDescription
generationintegerYes
profileVersionstringNo
unstartable”mark” | “clear”No
StatusMeaning
200The updated record
400The key or the body is invalid (INVALID_INSTANCE_KEY, VALIDATION_ERROR)
401Missing or invalid credential
403The credential is restricted to its own sandbox (SANDBOX_KEY_RESOURCE_FORBIDDEN)
404The key has no record (INSTANCE_NOT_FOUND)
409The record changed since it was read; instance holds the current record (INSTANCE_CONFLICT)

Release an instance key

DELETE /v1/instances/{key}

Forgets the key. Its sandbox is left as it is.

ParameterInRequiredTypeDescription
keypathYesstring1-200 characters: letters, digits and . _ : @ -, starting with a letter or digit.
StatusMeaning
204The key was released
400The key or the body is invalid (INVALID_INSTANCE_KEY, VALIDATION_ERROR)
401Missing or invalid credential
403The credential is restricted to its own sandbox (SANDBOX_KEY_RESOURCE_FORBIDDEN)
404The key has no record (INSTANCE_NOT_FOUND)

Bind a sandbox to an instance

PUT /v1/instances/{key}/binding

Records the sandbox that serves the key for the given generation. A key with no record starts at generation 1. Binding the sandbox that is already bound succeeds and clears a marked failed start. A member-paid line key can bind only the isolated sandbox it created.

ParameterInRequiredTypeDescription
keypathYesstring1-200 characters: letters, digits and . _ : @ -, starting with a letter or digit.

Request body (application/json):

FieldTypeRequiredDescription
generationintegerYes
sandboxIdstringYes
profileVersionstringNo
StatusMeaning
200The bound record
400The key or the body is invalid (INVALID_INSTANCE_KEY, VALIDATION_ERROR)
401Missing or invalid credential
403The credential cannot use this sandbox (SANDBOX_KEY_RESOURCE_FORBIDDEN, MEMBER_PAID_BOX_FORBIDDEN)
409The record changed since it was read; instance holds the current record (INSTANCE_CONFLICT)
503Member sandbox authority could not be checked (MEMBER_PAID_BOX_UNAVAILABLE)

Replace an instance’s sandbox

POST /v1/instances/{key}/replace

Retires the key’s sandbox of the given generation and opens the next generation with no sandbox. The retired sandbox is not deleted. A key with no record accepts generation 1 and starts at generation 2.

ParameterInRequiredTypeDescription
keypathYesstring1-200 characters: letters, digits and . _ : @ -, starting with a letter or digit.

Request body (application/json):

FieldTypeRequiredDescription
generationintegerYes
StatusMeaning
200The record at the next generation
400The key or the body is invalid (INVALID_INSTANCE_KEY, VALIDATION_ERROR)
401Missing or invalid credential
403The credential is restricted to its own sandbox (SANDBOX_KEY_RESOURCE_FORBIDDEN)
409The record changed since it was read; instance holds the current record (INSTANCE_CONFLICT)

Secrets

RouteDoes
GET /v1/secretsList secrets (names only, no values)
POST /v1/secretsCreate an encrypted secret
PUT /v1/secrets/{name}Replace a secret and re-key live sandboxes
DELETE /v1/secrets/{name}Delete a secret

List secrets (names only, no values)

GET /v1/secrets

StatusMeaning
200List of secret names
500Internal error

Create an encrypted secret

POST /v1/secrets

Request body (application/json):

FieldTypeRequiredDescription
namestringYes
valuestringYes
hostsarray of stringNo
headerstringNo
exposeInBoxtrueNo
proxySecretsarray of objectNo
reasonstringNo
StatusMeaning
201Secret created
400Validation error
409Secret already exists
500Internal error

Replace a secret and re-key live sandboxes

PUT /v1/secrets/{name}

ParameterInRequiredTypeDescription
namepathYesstring

Request body (application/json):

FieldTypeRequiredDescription
valuestringYes
hostsarray of stringNo
headerstringNo
exposeInBoxtrueNo
proxySecretsarray of objectNo
reasonstringNo
expectedUpdatedAtstringNo
StatusMeaning
200Secret created
400Validation error
404Not found
409Secret already exists
500Internal error
503Live re-key not acknowledged

Delete a secret

DELETE /v1/secrets/{name}

ParameterInRequiredTypeDescription
namepathYesstring
expectedUpdatedAtqueryNostring
StatusMeaning
200Secret deleted
404Not found
409Generation changed
500Internal error

SSH keys

RouteDoes
GET /v1/ssh-keysList SSH keys
POST /v1/ssh-keysAdd an SSH key
DELETE /v1/ssh-keys/{id}Delete an SSH key

List SSH keys

GET /v1/ssh-keys

StatusMeaning
200List SSH keys
500Internal error

Add an SSH key

POST /v1/ssh-keys

Request body (application/json):

FieldTypeRequiredDescription
namestringYes
publicKeystringYes
StatusMeaning
201SSH key created
400Validation error
409Conflict
500Internal error

Delete an SSH key

DELETE /v1/ssh-keys/{id}

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200SSH key deleted
404Not found
500Internal error

Startup scripts

RouteDoes
GET /v1/startup-scriptsList startup scripts
POST /v1/startup-scriptsCreate a startup script
GET /v1/startup-scripts/{id}Get a startup script
PUT /v1/startup-scripts/{id}Update a startup script
DELETE /v1/startup-scripts/{id}Delete a startup script
PATCH /v1/startup-scripts/{id}/toggleToggle a startup script enabled/disabled

List startup scripts

GET /v1/startup-scripts

StatusMeaning
200List of startup scripts
500Internal error

Create a startup script

POST /v1/startup-scripts

Request body (application/json):

FieldTypeRequiredDescription
namestringYes
descriptionstringNo
scriptType”bash” | “python” | “node” | “ruby” | “custom”No
contentstringYes
environmentsarray of stringNo
minCpuCoresnumber or nullNo
minRamGBnumber or nullNo
runOrderintegerNo
timeoutSecondsintegerNo
continueOnFailurebooleanNo
runAsRootbooleanNo
injectSecretsarray of stringNo
enabledbooleanNo
StatusMeaning
201Script created
400Validation error
403Tier restriction
500Internal error

Get a startup script

GET /v1/startup-scripts/{id}

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Script details
404Not found
500Internal error

Update a startup script

PUT /v1/startup-scripts/{id}

ParameterInRequiredTypeDescription
idpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
namestringNo
descriptionstringNo
scriptType”bash” | “python” | “node” | “ruby” | “custom”No
contentstringNo
environmentsarray of stringNo
minCpuCoresnumber or nullNo
minRamGBnumber or nullNo
runOrderintegerNo
timeoutSecondsintegerNo
continueOnFailurebooleanNo
runAsRootbooleanNo
injectSecretsarray of stringNo
enabledbooleanNo
StatusMeaning
200Script updated
400Validation error
403Tier restriction
404Not found
500Internal error

Delete a startup script

DELETE /v1/startup-scripts/{id}

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Script deleted
404Not found
500Internal error

Toggle a startup script enabled/disabled

PATCH /v1/startup-scripts/{id}/toggle

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Script toggled
404Not found
500Internal error

Lines

RouteDoes
GET /v1/linesList lines
POST /v1/linesCreate a line from a connection
GET /v1/lines/contextGet the current turn’s line context
GET /v1/lines/execution-keysList execution keys
GET /v1/lines/numbersList a connection’s phone numbers
GET /v1/lines/providersList line providers
GET /v1/lines/{lineId}Get a line
DELETE /v1/lines/{lineId}Release a line
PATCH /v1/lines/{lineId}Turn voice on or off
PUT /v1/lines/{lineId}/attachmentAttach a line
DELETE /v1/lines/{lineId}/attachmentDetach a line
PUT /v1/lines/{lineId}/attachment/reauthorizeChange an attachment’s execution key
DELETE /v1/lines/{lineId}/attachments/{attachmentId}Detach one attachment
GET /v1/lines/{lineId}/capturesList owner captures
GET /v1/lines/{lineId}/membersList line members
POST /v1/lines/{lineId}/membersAdd a line member
PATCH /v1/lines/{lineId}/members/{memberId}Update a line member
DELETE /v1/lines/{lineId}/members/{memberId}Remove a line member
GET /v1/lines/{lineId}/members/{memberId}/applicationGet a member’s application
PUT /v1/lines/{lineId}/members/{memberId}/applicationSelect a member’s application
DELETE /v1/lines/{lineId}/members/{memberId}/applicationClear a member’s application
GET /v1/lines/{lineId}/members/{memberId}/remindersGet a member’s reminder preferences
GET /v1/lines/{lineId}/messages/{messageId}Get a line message
POST /v1/lines/{lineId}/messages/{messageId}/application-dispatch/currentCheck an application dispatch
GET /v1/lines/{lineId}/outbox/{messageId}Get a send receipt
POST /v1/lines/{lineId}/remindSet a reminder for the current turn
POST /v1/lines/{lineId}/sendSend a message to a member
POST /v1/lines/{lineId}/sender-verificationsStart a sender verification
GET /v1/lines/{lineId}/sender-verifications/{testId}Get a sender verification
GET /v1/lines/{lineId}/threadsList line threads
GET /v1/lines/{lineId}/threads/{threadId}/approvalsList pending approvals
POST /v1/lines/{lineId}/threads/{threadId}/approvalsDecide a pending approval
GET /v1/lines/{lineId}/threads/{threadId}/messagesList thread messages

List lines

GET /v1/lines

A sandbox key lists only lines attached to its own sandbox. A workspace key lists only its workspace’s lines. profileId keeps lines attached with that profile and unattached lines whose clientReference starts with profile:<profileId>:.

ParameterInRequiredTypeDescription
sandboxIdqueryNostring
profileIdqueryNostring
StatusMeaning
200The caller’s lines
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403This key cannot list lines
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Create a line from a connection

POST /v1/lines

The connection must be active and support the transport. A repeated clientReference returns the existing line. A 409 that carries error.details.retryAfterSeconds can be retried after that many seconds.

Request body (application/json): one of 6 shapes; see the OpenAPI document.

StatusMeaning
200The line, new or existing
400The body is invalid, or the connection does not support the transport
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only an owner API key can do this
404The connection is not found (HUB_CONNECTION_MISSING)
409The connection is not active, or the reference, address or workspace already names another line
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
422The provider refused the line (HUB_PROVIDER_REJECTED)
429Too many requests (RATE_LIMITED)
500The connection could not be rechecked after a WhatsApp scope change (HUB_EXECUTOR_FAILURE); read the line, then retry
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment, or the provider failed (HUB_PROVIDER_FAILURE)

Get the current turn’s line context

GET /v1/lines/context

Send the line token a member’s sandbox receives for its current turn. Member addresses are never returned.

StatusMeaning
200The turn’s member, line, directory, capabilities and quotas
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403No current turn token was sent, or its turn has ended (HUB_RELAY_DENIED)
404The token’s sandbox no longer serves this line
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

List execution keys

GET /v1/lines/execution-keys

Account owner only. Lists the account’s active root Sandbox keys that can run an attached line. No key secret is returned.

StatusMeaning
200Keys that can run a line
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only the account’s root API key can do this
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

List a connection’s phone numbers

GET /v1/lines/numbers

Account owner only. Reading inventory never reserves or buys a number. exhaustive: false means the provider returned one page, so an owned number can be missing; create the line with its exact ID.

ParameterInRequiredTypeDescription
connectionIdqueryYesstring
transportqueryYes”imessage” | “sms” | “whatsapp”
StatusMeaning
200Numbers the connection owns
400connectionId or a phone transport is missing, or the provider does not support the transport
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only the account’s root API key can do this
404The connection is not found
409The connection is not active, changed during the lookup, or needs its webhook first
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines or number discovery are not configured on this deployment, or the provider failed

List line providers

GET /v1/lines/providers

Account owner only: send the account’s root API key.

StatusMeaning
200Provider and transport pairs this deployment binds
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only the account’s root API key can do this
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Get a line

GET /v1/lines/{lineId}

A sandbox key reads only a line attached to its own sandbox. A released line answers 404.

ParameterInRequiredTypeDescription
lineIdpathYesstring
StatusMeaning
200The line
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403This key cannot read lines
404The line is not found or not visible to this key
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Release a line

DELETE /v1/lines/{lineId}

Detach the line and turn its voice off first. released is false when the line was already released.

ParameterInRequiredTypeDescription
lineIdpathYesstring
StatusMeaning
200The release result
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only an owner API key can do this
404The line is not found or not visible to this key
409The line is attached, has voice on, or belongs to a managed number order
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Turn voice on or off

PATCH /v1/lines/{lineId}

On a metered or role-policy line, only the account’s root key can change voice.

ParameterInRequiredTypeDescription
lineIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
voiceobjectYes
StatusMeaning
200The line with its voice state
400The body is invalid
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only an owner API key can change a line, and only the account’s root key on a metered or role-policy line
404The line or its phone connection is not found
409The line is not active or is application-routed, or its connection is not active
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
422The voice provider refused (HUB_PROVIDER_REJECTED)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines or voice are not configured on this deployment, or the voice provider failed

Attach a line

PUT /v1/lines/{lineId}/attachment

Pass one execution target: sandboxId, instance, placement: "worker", a shared line with respond.application, or respond.kind: "none". Declare at least one member, unless a shared Telegram line installs its own. The calling API key becomes the execution key. Repeating an identical attach returns the existing attachment with 200. An allowance meter needs a plan on that meter before attaching.

ParameterInRequiredTypeDescription
lineIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
runAsKeyIdstringNoExecution key ID; an API key may name only itself
senderVerificationIdstringNoA verified sender test, consumed on attach
sandboxIdstringNoThe sandbox every member runs in
instanceobjectNoRun each member in their own named instance instead
placement”worker”NoRun turns without a sandbox, with the profile and connections only
connectionsarray of stringNoConnection IDs a worker turn may call
mode”personal” | “shared”Yespersonal: one owner member. shared: one thread each
payer”owner” | “member”No
membersarray of objectYes
unknownSenders”reject” | “guest”No
rolesobjectNoKeyed by role name: a lowercase word of up to 32 characters
respondobjectNo
limitsobjectNo
clientReferencestringNo
StatusMeaning
200The existing attachment
201The new attachment
400The body is invalid, a role is unknown, or the allowance meter has no plan
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403This key cannot attach the line, run the sandbox, name another execution key, or set a role policy or allowance
404The line, sandbox or stored profile is not found
409The line is not active, was attached concurrently, or is attached differently; detach first
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
422The line cannot verify senders (HUB_SENDER_VERIFICATION_UNSUPPORTED)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines or a required service are not configured on this deployment, or that service failed

Detach a line

DELETE /v1/lines/{lineId}/attachment

Detaches every attachment the line holds, or with If-Match: "lat_…" only that attachment. To detach only an attachment you observed, use DELETE /v1/lines/{lineId}/attachments/{attachmentId}.

ParameterInRequiredTypeDescription
lineIdpathYesstring
StatusMeaning
200detached is false when nothing was attached
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A metered or role-policy line needs the account’s root key or the line’s workspace key
404The line is not found or not visible to this key
409An application callback is still running; retry
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Change an attachment’s execution key

PUT /v1/lines/{lineId}/attachment/reauthorize

Send the request with the replacement API key, which becomes the execution key. Both expected IDs must match the attachment as last read.

ParameterInRequiredTypeDescription
lineIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
expectedAttachmentIdstringYes
expectedRunAsKeyIdstringYes
StatusMeaning
200The attachment with its new execution key
400The body is invalid
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only an API key can reauthorize, it cannot run the sandbox, or the line needs the account’s root key or its workspace key
404The line or sandbox is not found
409The expected attachment or execution key no longer matches
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines or the sandbox service are not configured on this deployment, or it failed

Detach one attachment

DELETE /v1/lines/{lineId}/attachments/{attachmentId}

Detaches only this attachment, so a retry never detaches its replacement.

ParameterInRequiredTypeDescription
lineIdpathYesstring
attachmentIdpathYesstring
StatusMeaning
200detached is false when it was already detached
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A metered or role-policy line needs the account’s root key or the line’s workspace key
404The line or attachment is not found
409An application callback is still running; retry
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

List owner captures

GET /v1/lines/{lineId}/captures

Lists the texts the line’s declared owner sent as idea <text>, oldest first. Pass the last page’s next as after to resume.

ParameterInRequiredTypeDescription
lineIdpathYesstring
afterqueryNostring
limitqueryNointeger
StatusMeaning
200A page of captures
400after is not a cursor from this route, or limit is not an integer from 1 to 200
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A sandbox key or turn token cannot read this
404The line is not found or not visible to this key
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

List line members

GET /v1/lines/{lineId}/members

An API key gets the members of the line’s current attachment. A turn’s line token gets the member directory, which has no addresses.

ParameterInRequiredTypeDescription
lineIdpathYesstring
StatusMeaning
200The members or the turn’s directory
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A sandbox key cannot read members, or the turn token has ended
404The line is not found or not visible to this key
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Add a line member

POST /v1/lines/{lineId}/members

Adding a member that exists with the same binding returns that member. A personal line has exactly one member.

ParameterInRequiredTypeDescription
lineIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
addressstringYesE.164 number or email address the member sends from
rolestringYes
labelstringNo
subjectIdstringNoOwner-authored customer identity, never a phone number
allowanceobjectNo
voiceConsentobjectNoOwner attestation of the member’s consent; voice lines
StatusMeaning
201The member, new or existing
400The body is invalid, the role is unknown, the line is personal, or the address does not fit the transport
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A metered or role-policy line needs the account’s root key or the line’s workspace key
404The line is not found or not attached
409The address or subjectId already belongs to another member binding
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Update a line member

PATCH /v1/lines/{lineId}/members/{memberId}

ParameterInRequiredTypeDescription
lineIdpathYesstring
memberIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
rolestringNo
labelstringNo
StatusMeaning
200The updated member
400The body is invalid, the role is unknown, or the role does not fit the line
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A metered or role-policy line needs the account’s root key or the line’s workspace key
404The line, attachment or member is not found
409An application callback for the member is still running, or a shared application line’s owner changes only with a newly verified sender
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Remove a line member

DELETE /v1/lines/{lineId}/members/{memberId}

A personal line’s member and a role-policy line’s last owner cannot be removed; detach the line instead.

ParameterInRequiredTypeDescription
lineIdpathYesstring
memberIdpathYesstring
StatusMeaning
200The member is removed
400This member cannot be removed
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A metered or role-policy line needs the account’s root key or the line’s workspace key
404The line, attachment or member is not found
409An application callback for the member is still running, or a shared application line’s owner changes only with a newly verified sender
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Get a member’s application

GET /v1/lines/{lineId}/members/{memberId}/application

Account owner only. Pass memberRevision as expectedMemberRevision when changing the selection.

ParameterInRequiredTypeDescription
lineIdpathYesstring
memberIdpathYesstring
StatusMeaning
200The member’s revision and selection
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only the account’s root API key can do this
404The line or active member is not found
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Select a member’s application

PUT /v1/lines/{lineId}/members/{memberId}/application

Account owner only. The change applies only while expectedSelectionId and expectedMemberRevision match. Bindings that start with line-grant: are reserved.

ParameterInRequiredTypeDescription
lineIdpathYesstring
memberIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
expectedSelectionIdstring or nullYes
expectedMemberRevisionstringYes
subjectIdstringYes
applicationobjectYes
StatusMeaning
200The new selection
400The body is invalid, the URL is not public HTTPS, or the binding is reserved
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only the account’s root API key can select, or the member cannot use that application
404The line, active attachment or member is not found
409The selection or member revision changed
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines or shared applications are not enabled on this deployment

Clear a member’s application

DELETE /v1/lines/{lineId}/members/{memberId}/application

Account owner only. The change applies only while both expected values match.

ParameterInRequiredTypeDescription
lineIdpathYesstring
memberIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
expectedSelectionIdstringYes
expectedMemberRevisionstringYes
StatusMeaning
200The selection is cleared
400The body is invalid
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only the account’s root API key can do this
404The line or active member is not found
409The selection or member revision changed
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Get a member’s reminder preferences

GET /v1/lines/{lineId}/members/{memberId}/reminders

enabled is true once the member texts REMINDERS ON with a timezone on the current attachment.

ParameterInRequiredTypeDescription
lineIdpathYesstring
memberIdpathYesstring
StatusMeaning
200The member’s reminder preferences
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A sandbox key or turn token cannot read this
404The line or member is not found
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines or the line outbox are not configured on this deployment

Get a line message

GET /v1/lines/{lineId}/messages/{messageId}

ParameterInRequiredTypeDescription
lineIdpathYesstring
messageIdpathYesstring
StatusMeaning
200The message
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A sandbox key or turn token cannot read this
404The line or message is not found
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Check an application dispatch

POST /v1/lines/{lineId}/messages/{messageId}/application-dispatch/current

Send the line application’s callback secret as the Bearer token, not an API key. current: false means the dispatch is stale and must not be admitted.

ParameterInRequiredTypeDescription
lineIdpathYesstring
messageIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
attachmentIdstringYes
memberIdstringYes
memberRevisionstringYes
senderAddressstringYes
textSha256stringYes
bindingstringYes
dispatchFencestringYes
dispatchDeadlinestringYes
StatusMeaning
200Whether the dispatch may still be admitted
400The body is invalid
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403The callback secret is missing or wrong, or the application binding is inactive
413The body is larger than 4 KiB (HUB_INVALID_INPUT)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Get a send receipt

GET /v1/lines/{lineId}/outbox/{messageId}

reply.answer holds the first coded answer once the member replies.

ParameterInRequiredTypeDescription
lineIdpathYesstring
messageIdpathYesstring
StatusMeaning
200The send’s receipt
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A sandbox key or turn token cannot read this
404The line or send is not found
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines or the line outbox are not configured on this deployment, or the send’s record is incomplete (HUB_OUTBOX_MISSING)

Set a reminder for the current turn

POST /v1/lines/{lineId}/remind

Needs the line token of an owner’s current turn, and the owner must have reminders on. The member’s agent wakes at notBefore in the same session and writes the reminder.

ParameterInRequiredTypeDescription
lineIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
textstringYes
notBeforestringYesA future time
idempotencyKeystringYes
StatusMeaning
202The queued reminder
400The body is invalid, or notBefore is not in the future
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403No owner turn token was sent, or its turn has ended (HUB_RELAY_DENIED)
409Reminders are off, the key names another request, or the line’s reply gate forbids it
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Send a message to a member

POST /v1/lines/{lineId}/send

Queues a proactive message; the receipt is not proof of delivery. The member must have texted REMINDERS ON with a timezone. Repeating an idempotencyKey returns the first send, and the same key with another request answers 409 HUB_IDEMPOTENCY_CONFLICT. An owner API key sends the owner body; a turn’s line token sends the turn body.

ParameterInRequiredTypeDescription
lineIdpathYesstring

Request body (application/json): one of 2 shapes; see the OpenAPI document.

StatusMeaning
202The queued send
400The body is invalid, or notBefore is too far away
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only an owner API key or a current turn’s line token can send, and the turn’s role may not relay
404The line, attachment or member is not found
409The member has not opted in, is not active, or has no retained conversation, or the key, code, image or reply gate conflicts
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests, or a recipient or line send limit is reached (HUB_OUTBOX_LIMIT)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines or the line outbox are not configured on this deployment

Start a sender verification

POST /v1/lines/{lineId}/sender-verifications

Needs an owner API key, and the line must be unattached. Text testText to the line from the handset to enroll before expiresAt, then answer the private code the line sends back. A new test replaces the open one. Attach with the verified testId as senderVerificationId.

ParameterInRequiredTypeDescription
lineIdpathYesstring

Request body: application/json.

StatusMeaning
201The test to send
400The body is not empty or {}
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only an owner API key can do this
404The line is not found or not visible to this key
409The line is not active (HUB_LINE_INACTIVE), is attached, or its connection changed
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
422The line’s provider or transport cannot verify senders (HUB_SENDER_VERIFICATION_UNSUPPORTED)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Get a sender verification

GET /v1/lines/{lineId}/sender-verifications/{testId}

Needs the API key that started the test. approvedSender is present only in state verified; keep it out of browser-visible state.

ParameterInRequiredTypeDescription
lineIdpathYesstring
testIdpathYesstring
StatusMeaning
200The test’s state and proof times
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only an owner API key can do this
404The line or test is not found for this key
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

List line threads

GET /v1/lines/{lineId}/threads

ParameterInRequiredTypeDescription
lineIdpathYesstring
StatusMeaning
200Threads, most recent message first
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A sandbox key or turn token cannot read this
404The line is not found or not visible to this key
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

List pending approvals

GET /v1/lines/{lineId}/threads/{threadId}/approvals

Account owner only. Lists the agent actions in the thread’s session that wait for the owner’s decision.

ParameterInRequiredTypeDescription
lineIdpathYesstring
threadIdpathYesstring
StatusMeaning
200The pending requests
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only the account’s root API key can do this
404The line is not attached, or the thread has no current approval session
409The thread’s approval session changed
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Approvals are not available on this deployment

Decide a pending approval

POST /v1/lines/{lineId}/threads/{threadId}/approvals

Only the account owner’s signed-in browser session can decide, so every API key gets 403.

ParameterInRequiredTypeDescription
lineIdpathYesstring
threadIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
decision”approve” | “deny”Yes
requestDigeststringYes
csrfstringYes
StatusMeaning
200The session’s acknowledgement
400The body is invalid or larger than 4 KiB
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403Only the account owner’s signed-in session can decide
404The line is not attached, or the thread has no current approval session
409The request is no longer awaiting approval
413The request body is larger than 256 KiB (PAYLOAD_TOO_LARGE)
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Approvals are not available on this deployment

List thread messages

GET /v1/lines/{lineId}/threads/{threadId}/messages

Returns the latest messages, newest first, without paging.

ParameterInRequiredTypeDescription
lineIdpathYesstring
threadIdpathYesstring
StatusMeaning
200The messages
401No Bearer token was sent (LINES_API_KEY_REQUIRED), or it is not valid (HUB_UNAUTHENTICATED)
403A sandbox key or turn token cannot read this
404The line or thread is not found
429Too many requests (RATE_LIMITED)
502Lines did not answer in time, failed or redirected (PLATFORM_UNAVAILABLE); retry
503Lines are not configured on this deployment

Teams

RouteDoes
GET /v1/teamsList teams the current user belongs to
POST /v1/teamsCreate a team owned by the current user
DELETE /v1/teams/invitations/{id}Revoke a pending invitation
GET /v1/teams/invitations/{token}Preview an invitation (team name + inviter) by token
POST /v1/teams/invitations/{token}/acceptAccept a team invitation
GET /v1/teams/{id}Get a team the user belongs to
PATCH /v1/teams/{id}Update team metadata
DELETE /v1/teams/{id}Delete a team (owner only)
GET /v1/teams/{id}/egressGet team egress policy
PUT /v1/teams/{id}/egressSet team egress policy
DELETE /v1/teams/{id}/egressClear team egress policy
GET /v1/teams/{id}/invitationsList invitations for the team
POST /v1/teams/{id}/invitationsInvite a user to the team by email
POST /v1/teams/{id}/leaveLeave a team (non-owner members only)
GET /v1/teams/{id}/membersList team members
PATCH /v1/teams/{id}/members/{memberId}Update a team member’s role or status
DELETE /v1/teams/{id}/members/{memberId}Remove a team member
GET /v1/teams/{id}/secretsList team secret names (values never returned)
PUT /v1/teams/{id}/secrets/{name}Create or replace a team secret
DELETE /v1/teams/{id}/secrets/{name}Delete a team secret
POST /v1/teams/{id}/secrets/{name}/revealReveal the plaintext value (owner/admin only, audit-logged)
GET /v1/teams/{id}/templatesList team golden-path templates
POST /v1/teams/{id}/templatesCreate a team golden-path template (owner/admin only)
DELETE /v1/teams/{id}/templates/{templateId}Delete a team golden-path template (owner/admin only)
POST /v1/teams/{id}/transferTransfer team ownership (current owner only)

List teams the current user belongs to

GET /v1/teams

StatusMeaning
200Teams list
500Internal error

Create a team owned by the current user

POST /v1/teams

Request body (application/json):

FieldTypeRequiredDescription
namestringYes
orgIdstringNo
StatusMeaning
201Team created
400Validation error
500Internal error

Revoke a pending invitation

DELETE /v1/teams/invitations/{id}

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Revoked
403Insufficient permission
404Not found
409No longer pending
500Internal error

Preview an invitation (team name + inviter) by token

GET /v1/teams/invitations/{token}

ParameterInRequiredTypeDescription
tokenpathYesstring
StatusMeaning
200Invitation preview
404Not found
500Internal error

Accept a team invitation

POST /v1/teams/invitations/{token}/accept

ParameterInRequiredTypeDescription
tokenpathYesstring
StatusMeaning
200Accepted
403Email mismatch
404Invitation not found
409Invitation terminal state
500Internal error

Get a team the user belongs to

GET /v1/teams/{id}

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Team
403Not a team member
404Not found
500Internal error

Update team metadata

PATCH /v1/teams/{id}

ParameterInRequiredTypeDescription
idpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
namestringNo
StatusMeaning
200Updated
400Validation error
403Insufficient permission
404Not found
500Internal error

Delete a team (owner only)

DELETE /v1/teams/{id}

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Deleted
403Insufficient permission
404Not found
500Internal error

Get team egress policy

GET /v1/teams/{id}/egress

Returns the team’s default egress policy, or null if none is set.

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Egress policy retrieved
403Forbidden
404Team not found
500Internal error

Set team egress policy

PUT /v1/teams/{id}/egress

Set or update the team’s default egress policy. Only owners and admins.

ParameterInRequiredTypeDescription
idpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
mode”open” | “strict” | “blocked”Yes
allowDomainsarray of string or objectNo
includeImplicitDomainsbooleanNo
StatusMeaning
200Policy updated
400Invalid policy
403Forbidden
404Team not found
500Internal error

Clear team egress policy

DELETE /v1/teams/{id}/egress

Remove the team’s custom egress policy. Sandboxes will fall back to platform defaults.

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Policy cleared
403Forbidden
404Team not found
500Internal error

List invitations for the team

GET /v1/teams/{id}/invitations

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Invitations
403Insufficient permission
500Internal error

Invite a user to the team by email

POST /v1/teams/{id}/invitations

ParameterInRequiredTypeDescription
idpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
emailstringYes
role”admin” | “member” | “viewer”Yes
ttlHoursintegerNo
StatusMeaning
201Invitation created
400Validation error
403Insufficient permission
409Duplicate or existing member
500Internal error

Leave a team (non-owner members only)

POST /v1/teams/{id}/leave

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Left
400Validation error
404Not found
500Internal error

List team members

GET /v1/teams/{id}/members

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Member list
403Not a team member
500Internal error

Update a team member’s role or status

PATCH /v1/teams/{id}/members/{memberId}

ParameterInRequiredTypeDescription
idpathYesstring
memberIdpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
role”admin” | “member” | “viewer”No
status”active” | “removed”No
StatusMeaning
200Updated
400Validation error
403Insufficient permission
404Not found
500Internal error

Remove a team member

DELETE /v1/teams/{id}/members/{memberId}

ParameterInRequiredTypeDescription
idpathYesstring
memberIdpathYesstring
StatusMeaning
200Removed
400Validation error
403Insufficient permission
404Not found
500Internal error

List team secret names (values never returned)

GET /v1/teams/{id}/secrets

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Secret list
403Not a team member
500Internal error
501Team secrets not configured

Create or replace a team secret

PUT /v1/teams/{id}/secrets/{name}

ParameterInRequiredTypeDescription
idpathYesstring
namepathYesstring

Request body (application/json):

FieldTypeRequiredDescription
valuestringYes
hostsarray of stringNo
headerstringNo
exposeInBoxtrueNo
proxySecretsarray of objectNo
reasonstringNo
StatusMeaning
200Upserted
400Validation error
403Insufficient permission
409Conflict
500Internal error
501Team secrets not configured
503Live re-key not acknowledged

Delete a team secret

DELETE /v1/teams/{id}/secrets/{name}

ParameterInRequiredTypeDescription
idpathYesstring
namepathYesstring
StatusMeaning
200Deleted
403Insufficient permission
404Not found
500Internal error
501Team secrets not configured

Reveal the plaintext value (owner/admin only, audit-logged)

POST /v1/teams/{id}/secrets/{name}/reveal

ParameterInRequiredTypeDescription
idpathYesstring
namepathYesstring
StatusMeaning
200Plaintext value
403Insufficient permission
404Not found
500Internal error
501Team secrets not configured

List team golden-path templates

GET /v1/teams/{id}/templates

ParameterInRequiredTypeDescription
idpathYesstring
StatusMeaning
200Template list
403Not a team member
500Internal error
501Team templates not configured

Create a team golden-path template (owner/admin only)

POST /v1/teams/{id}/templates

ParameterInRequiredTypeDescription
idpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
namestringYes
descriptionstringNo
snapshotIdstringYes
sourceSandboxIdstringYes
environmentstringNo
configobjectNo
StatusMeaning
201Template created
400Validation error
403Insufficient permission
409Conflict
500Internal error
501Team templates not configured

Delete a team golden-path template (owner/admin only)

DELETE /v1/teams/{id}/templates/{templateId}

ParameterInRequiredTypeDescription
idpathYesstring
templateIdpathYesstring
StatusMeaning
200Deleted
403Insufficient permission
404Not found
500Internal error
501Team templates not configured

Transfer team ownership (current owner only)

POST /v1/teams/{id}/transfer

ParameterInRequiredTypeDescription
idpathYesstring

Request body (application/json):

FieldTypeRequiredDescription
newOwnerCustomerIdstringYes
StatusMeaning
200Ownership transferred (no content)
400Validation error
403Not the current owner
404Target not a member
500Internal error

Next steps