Guest Machines
API reference

API reference

The supported HTTP contract for Guest Machines integrations.

Every endpoint documented here is part of the supported public contract and carries a compatibility promise. Fields may be added to requests and responses; they will not be removed or repurposed, and operation identifiers are frozen so generated clients keep compiling.

Do not depend on an endpoint just because you observed the product calling it. Undocumented routes can change or disappear without notice. If you need something that is not here, ask before depending on it.

Base URL and versioning

https://api.guestmachines.com

The version lives in the path, and the current version is v1. A breaking change would appear as a new version rather than as a change to this one.

What the contract covers

The supported surfaces are enough to authenticate clients, discover capabilities, manage connectors, run work, and observe it:

SectionWhat it does
AuthenticationRegister delegated clients, record human consent, and exchange tokens
CapabilitiesNegotiate supported features and discover available models and tools
ConnectorsRegister, inspect, probe, share, and manage remote MCP connectors
AgentsCreate and update agents, invoke one, list its runs
ChatsChat with an agent, and edit, retry and reorder messages still waiting
WorkflowsCreate, update, and delete workflows; run and rerun them
RunsUpload inputs; observe, steer, and control runs; retrieve artifacts
WebhooksReceive signed, at-least-once platform event notifications
TriggersStart configured work from an external system

Delegated tokens can provision and update user-owned agents, workflows, and MCP connectors, and delete workflows. A delegated application representing a current organization admin or owner can also manage the connector library with an explicit publish grant. Agent deletion, agent revision restore, webhook destination management, budgets, and policies remain deliberately absent; use the console for those operations.

The Runs section also exposes the complete public file handoff: upload raw bytes as a ready artifact, attach its returned ID through artifact_inputs, list visible artifacts and run bindings, and create short-lived download or preview URLs. Only the routes listed in this reference are supported for integrations.

Credentials

Integrations use one of three reusable bearer credentials:

CredentialPrefixIdentity
User API keygsmc_uk_The member who created it, with their current permissions.
Automation account keygsmc_sk_The organization itself. No user. The reference calls it ServicePrincipalKey.
Delegated tokengsmc_dt_A specific user, through an external application.

Each is bound to one organization and needs no X-Org-Id header; a user API key rejects a conflicting one. Authentication covers how to choose between them.

The Authentication section also documents a UserSession scheme for the human-only operations where an admin registers a delegated client and a member reviews, grants, or withdraws consent. This is a short-lived browser credential, not something an integration should capture or store. Only a direct user session can use X-Org-Id to select among the user's active memberships.

What a run without a user identity can do

The agent and workflow execution endpoints accept any of these credentials. A run started with an automation account key has no acting user and is attributed to that key. In a personal workspace, an active automation account can use the sole owner's agent memory for agents it is authorized to invoke. That memory permission is checked on every operation and does not grant human identity or personal Google credentials. Automation accounts in shared workspaces cannot use private agent memory. User runs require the agent owner or a current workspace administrator; sharing an agent does not share its memory.

Private API execution, which uses the owner's own app accounts, has a separate contract. On the Private API Tasks page (under Triggers), the owner reviews a fixed task and binds it to one user API key. That key can call POST /api/v1/private-api-tasks/{task_id}/runs with {"request_id":"<UUID>"}. Reuse the UUID when retrying; use a fresh UUID for new work. Other keys, automation accounts and delegated OAuth tokens cannot use that consent. The API cannot change the task's input, agent, app permissions or approval mode. One active or paused run blocks new starts, and the reviewed hourly limit also applies. Actions that ask the owner first, such as sending email, still need their approval. The response links to an owner-private run; holding the key grants the key's existing owner-scoped read access, so keep it secret.

Two tools have no such fallback, because they need a specific human rather than a lane to write into:

ToolBehaviour with an automation account key
ask_userReturns a tool error — there is nobody to ask. The agent decides on its own or fails with a reason.
send_emailReturns a tool error — sending needs a verified sender identity.

If an agent, or a workflow step, depends on either, start the run with a delegated token so it has a user behind it. For ask_user, a workflow step can instead name the member its runs ask.

Each endpoint states which credentials drive it.

Scopes

An automation account or delegated token carries scopes of the form resource:action. It can call only the operations this reference lists for it, and only while it holds every scope the operation names; every other endpoint answers 403, however it is scoped. The scopes this contract uses:

ScopeGrants
agents:readRead agents and their runs
agents:createCreate an agent owned by the delegated user
agents:editUpdate an authorized agent configuration
agents:invokeRun an agent
chats:listList the user's chats
chats:readRead a chat, its messages, and the messages still waiting
chats:createStart a chat (with agents:invoke for its agent)
chats:editSend messages (with agents:invoke), change waiting ones, or stop a turn (with runs:edit)
chats:deleteDelete a chat
mcp_servers:listList the user's private connectors or the organization library
mcp_servers:readRead an accessible connector without exposing its credential
mcp_servers:createRegister a private connector owned by the delegated user
mcp_servers:editUpdate or probe an accessible connector
mcp_servers:deleteDelete a connector owned by the delegated user
mcp_servers:publishPublish or unpublish organization-library connectors
workflows:listEnumerate workflows
workflows:readRead a workflow and its runs
workflows:createCreate a workflow owned by the delegated user
workflows:editUpdate an authorized workflow
workflows:deleteDelete an authorized workflow
workflows:invokeRun or rerun a workflow
runs:listEnumerate runs
runs:createUpload an immutable artifact for use as a run input
runs:readRead a run, its results, files, and sandbox operation results
runs:read_resultsAllow an automation account to read MCP results from its own non-private runs
runs:editCancel, resume, govern, or control a run's sandbox

Scopes on other resources, such as audit, usage, env_vars, knowledge, memory, schedules or webhooks, grant nothing, because no operation here uses them. Grant the narrowest set that works. A wildcard action such as agents:* is accepted and includes destructive actions. MCP publication and result content are separate: mcp_servers:* does not include mcp_servers:publish, and runs:* does not include runs:read_results.

Configuration writes need the right identity

Creating a saved configuration needs a user owner, so agent, workflow, and MCP connector create operations accept a delegated token but not an automation account key. The new resource belongs to the represented user. Creating an MCP connector directly in the organization library additionally requires mcp_servers:publish and a current admin or owner role.

Updates follow the existing resource rules. A delegated token can update only its user's resources. An automation account can update an organization-shared agent when its edit scope covers it, but it cannot attach a user's private connector while doing so. Updating or deleting a workflow needs a user who owns it or is a workspace admin. Organization-library connectors remain attachable.

Creating a workflow, changing its definition, or sharing it also checks that the user can run every agent and workflow the definition names, fallback agents included. Grant agents:invoke and workflows:invoke for the ones it uses.

Scopes are not sufficient on their own

Both visibility and scopes restrict access. An automation account can never reach a resource whose visibility is private, whatever it holds. Agents and workflows are private when created, so a new automation account typically sees nothing until you share the resource with the organization or, for an agent, set it to restricted visibility and add the automation account to it. Chats belong to the member who started them, so an automation account never reaches one. An owner or admin can also limit an automation account to specific agents and workflows.

The practical consequence is that list endpoints omit what the caller cannot see rather than failing. An empty list means one of three things — the workspace is empty, the scope is missing, or every match is still private — and only the second produces an error anywhere.

Conventions

Identifiers are UUIDs, except runs, which are integers.

Collections accept limit (1–100, default 50) and offset, and return a total alongside the page. The total counts what the caller can see, not what exists.

Timestamps are ISO 8601 in UTC.

Every response carries X-Request-Id. Log it and include it when reporting a problem; error bodies repeat it.

Execution is asynchronous

Starting an agent answers 202 with a run, not with a result. The request is validated before it is accepted, so limit, budget, and authorization errors are returned immediately. Poll run progress for its current state, or subscribe to the event stream for live lifecycle events.

Control a run's sandbox programmatically

An API client can temporarily run commands and read or write files in an existing run's sandbox. It needs edit access to the run. Interactive desktop and terminal access are available separately in the app.

Use this flow:

  1. Retrieve sandbox status with runs:read and confirm the run has an available sandbox.
  2. Acquire control with runs:edit and a stable request_id, then poll the returned control until it is active.
  3. Submit one command, file read, file write, or directory listing. Poll the returned operation instead of holding the request open.
  4. Send a heartbeat while using the sandbox, and release it when finished so the agent can continue.

An automation account key, delegated token, or user API key must first be authorized for the run. The exact bearer credential that acquires control then owns it. Another credential for the same organization—or even the same user—cannot adopt it, and a signed-in browser session cannot call this API. Human and programmatic control are mutually exclusive. Commands use the run's existing files and environment and follow its network and spend limits. Control ends when its maximum lifetime expires.

Only one operation can be pending or running at a time. Commands have a 600-second maximum and 100 KiB combined stdout/stderr cap. File reads and writes are whole UTF-8 values up to 5 MiB; directory listings contain at most 1,000 entries and 100 KiB. A relative guest path starts at /home/user; an absolute path still names only the guest machine, including locations such as /tmp. Results become unavailable 24 hours after an operation finishes. Its status and metadata remain available.

A 202 means the request was accepted; poll the returned control or operation until it finishes. If it remains requested or pending, retry the exact payload and request_id to continue the same request. Operation status unknown is terminal: Guest Machines could not determine whether the command or write took effect, so never retry it blindly. The affected sandbox cannot be used again. Control responses are always private, no-store.

Answer human interactions

A run can stop at awaiting_user_input when ask_user needs typed answers, or at awaiting_tool_approval before a governed tool call. These pauses survive reconnects and service restarts.

Start interactive work with a delegated token. When the run status or a webhook reports a pause:

  1. Retrieve the pending interaction with runs:read.
  2. Render the returned user_input questions or tool_approval action. Tool arguments are bounded and redacted, but they should still be treated as untrusted display content.
  3. Answer that interaction with runs:edit, returning its opaque interaction_id unchanged.
  4. Continue observing the run. A 202 means the decision was accepted; resume_status reports whether the run resumed.

In a chat, a newer question replaces an earlier one that is still waiting: the earlier run is cancelled with error code run.question_superseded, and an answer sent for it gets 409 with that code.

For user input, selected carries the option's zero-based suggestion_index, while custom carries a value and is accepted only when the question sets allow_other. skipped uses the question's recommended suggestion and carries neither; a question that offers no suggestions has no recommended default, so it must be answered with custom and cannot be skipped or omitted. A tool approval needs only approved; a denial may also include denial_reason.

Treat 409 as a stale interaction: retrieve and review the current request instead of resubmitting the old decision. If a 202 returns resume_status=failed, the answer remains committed and the ordinary resume operation can retry resuming without changing the accepted decision. Generic resume cannot supply or bypass a pending answer.

Only the user the run asks can read or answer a question: the user who started it, or the member its workflow step names. A tool approval can also be read and answered by a current organization owner or admin through their own session or user API key, unless the run is private: a run in a member's chat, one started by a private automation, or any run that uses a member's own accounts and credentials (their runs of their own private agent). A delegated token never carries admin power, so it can answer only its own user's runs, and an automation account cannot answer at all.

Steer a working run

The user who started a run can send it a message while it works, as Send now does in a chat: the run reads it before its next step and takes it into account. Send the message with runs:edit; a 202 returns it with status pending. Retrieve it or list the run's messages with runs:read to see what became of it:

StatusMeaning
pendingWaiting for the run to read it before its next step.
deliveredThe run read it; delivered_at says when.
undeliveredThe run ended before reading it.
requeuedThe run was a chat's turn and ended before reading it, so it waits for the chat's next turn.

Only a pending or running agent run that no other run or workflow started takes a message. A run waiting at awaiting_user_input or awaiting_tool_approval doesn't: answer its interaction instead. A 409 with code run.not_steerable means the run can't take a message now, and run.steering_full means 20 messages already wait for it to read them. Send a client_ref so a retry returns the stored message instead of sending it twice.

Only the run's starter can steer it or read its messages, through their own session or user API key, or a delegated token acting for them. Workspace owners and admins can't steer another user's run, and automation accounts can't steer. A message a chat's turn doesn't read becomes the chat's next turn, so a delegated token steering a chat's turn also needs chats:edit and agents:invoke; without them it gets 403. The capabilities document reports this as runs.live_steering.

Chat with an agent

A chat is a conversation between one member and an agent, as in the app. Start one, then send it messages: a 202 returns the stored message, which waits until one of the chat's turns takes it in. The agent's answer arrives in the chat's messages.

Messages sent while a turn works wait in the chat's queue. List them, then edit, delete, retry or reorder them before a turn takes them in. Every open app tab shows the change at once. Chat with an agent walks through it.

A chat is private to the member who started it: only they can open it, send to it or change its queue, through their user API key or a delegated token acting for them. A workspace owner or admin can only stop the running turn of another member's chat or delete it, signed in to the app, and can't read it. A turn runs with the credential that sent its message: charged to that key, or as that delegated application. In a chat with the Concierge, a delegated application's turns stay within the member's live consent to that application. Threads between agents aren't part of this API, and a user API key gets 403 from them.

Approve or deny a run's tools

An unattended run that will use high-risk tools with nobody watching stops before it starts until someone approves its tools. The API calls this plan approval; the app shows it as "Approve tools for this run". Only runs nobody can be asked about stop this way: runs started by an automation account, a schedule, or a webhook. A run started with a user's API key or a delegated token asks that user at each high-risk tool call instead. When a run reports awaiting_plan_approval or paused_for_replan, retrieve its active plan before deciding. You can approve or deny the run's tools with runs:edit. Approval attempts to resume the run; denial leaves it paused at paused_for_replan.

To change the tools, replan the run. Copy the two values from replan_fence into the request, and treat 409 as a signal to read and review the newer plan. You may replace the complete tool selection, but cannot submit a natural-language rewrite.

Only the user who started the run can replan it, using their session or delegated token. An automation account can read, approve, and deny organization runs when scoped, but it cannot replace a plan.

Idempotency

Execution starts accept an Idempotency-Key header, and artifact uploads require one. Sandbox control acquisition and each command or file operation use a body request_id UUID instead. Generate one stable value per intended operation and reuse it only to retry that exact operation.

The key is scoped to the caller and target context, so two integrations cannot adopt each other's runs or uploads through a shared value. A replay must present the original payload or upload fingerprint: reusing a key with different input answers 409 rather than creating a second resource.

Rate limits

Expensive operations — starting agent and workflow runs, and programmatically controlling a run sandbox — are throttled per machine credential, on top of the platform's concurrency limits and the organization's own daily-run, daily-spend, and budget limits.

Runs started past the concurrency limit wait in a queue (status=pending with queued_since set) and start on their own. A 429 carries Retry-After when the limit has a known window: a full queue always sets it; daily caps and budget stops usually do not, because they clear at midnight UTC or need an operator to act. A 503 with rate_limiter_unavailable means the limiter itself is degraded and the request was refused rather than waved through; back off and retry.

Errors and retries covers which failures are worth retrying.

Compatibility

Within v1, we may add endpoints, add optional request fields, add response fields, and add new values to enumerations. Treat unknown response fields and unknown enum values as data to ignore rather than as errors, or an additive change will break your client.

We will not remove a documented field, change its type, change an operation identifier, or narrow an existing response. Anything that would require you to edit code arrives as a new version.

Endpoints outside this reference carry none of the above.

On this page