Run Droid with the Execute API
Start a headless Droid turn with one API call, on a fresh computer from an Environment, an existing computer, or an existing session.
The Droid Execute API runs a Droid turn with a single request. You send a prompt and a target, and Factory finds or provisions the computer, starts or continues a session, and sends your prompt. You don't need to create a computer or session first.
Use it to trigger Droid from CI pipelines, internal tools, webhooks, or scripts. The Execute a Droid turn reference lists every request field, response field, and error status. This page explains how to use it.
Authentication
Every request needs a Factory API key in the Authorization: Bearer header. Generate one in the Factory API keys settings and export it as FACTORY_API_KEY.
Service account API keys work too. The session, and any computer created for it, is owned by the service account.
Execute a Droid turn
POST https://api.factory.ai/api/v0/droid/executeThe request returns 202 Accepted once the turn has started. Droid keeps working in the background, so poll the session to follow progress and read the results.
The response includes sessionId, computerId, and messageId, the ID of the user message created from your prompt.
model and reasoningEffort apply only when the request starts a new session. Sending either one with a session target returns 400.
Targets
target is an object with a kind field and exactly one matching ID field.
kind | ID field | Behavior |
|---|---|---|
environment | environmentId | Provisions a fresh computer from the Environment's active build, then starts a new session on it. |
computer | computerId | Starts a new session on an existing computer you own. |
session | sessionId | Sends the prompt as a follow-up message in an existing session you own. The session keeps its computer, model, and history. |
An environment target waits for the new computer to finish provisioning before it returns, so expect that request to take longer than the other targets. The computer is not listed in your Droid Computers and is cleaned up after it goes idle. To keep working on it, send follow-ups with a session target and the returned sessionId.
Look up IDs with the rest of the API: GET /api/v0/environments lists Environments, and GET /api/v0/computers lists computers.
Examples
Start a session on a fresh computer from an Environment:
curl -X POST "https://api.factory.ai/api/v0/droid/execute" \
-H "Authorization: Bearer $FACTORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Fix the failing unit tests in packages/api and open a pull request.",
"target": { "kind": "environment", "environmentId": "<environment-id>" },
"model": "claude-opus-5-5",
"reasoningEffort": "medium"
}'Start a session on a computer you already have:
curl -X POST "https://api.factory.ai/api/v0/droid/execute" \
-H "Authorization: Bearer $FACTORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Summarize the open TODOs in this repository.",
"target": { "kind": "computer", "computerId": "<computer-id>" }
}'Send a follow-up to an existing session:
curl -X POST "https://api.factory.ai/api/v0/droid/execute" \
-H "Authorization: Bearer $FACTORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Also add a regression test for the bug you fixed.",
"target": { "kind": "session", "sessionId": "<session-id>" }
}'Poll for results
The execute call only starts the turn. Use the Droid Sessions API with the returned IDs to follow it:
- 1Poll the session status
Call
GET /api/v0/sessions/{sessionId}?computerId={computerId}. Thestatusfield ispendingorrunningwhile Droid works andidlewhen it stops. - 2Read the transcript
Call
GET /api/v0/sessions/{sessionId}/messages?computerId={computerId}to read the messages.
Right after the call, the session can still report idle from the previous turn, especially when you send a follow-up to an existing session. Treat the turn as complete only when the session is idle and the transcript has an assistant message after the user message whose id is the returned messageId.
A newly created session can briefly return 404 before it is visible. Retry until it appears.
const headers = {
Authorization: `Bearer ${process.env.FACTORY_API_KEY}`,
"Content-Type": "application/json",
};
const base = "https://api.factory.ai/api/v0";
const started = await fetch(`${base}/droid/execute`, {
method: "POST",
headers,
body: JSON.stringify({
prompt: "Upgrade lodash to the latest version and run the tests.",
target: { kind: "environment", environmentId: "<environment-id>" },
}),
});
if (started.status !== 202) throw new Error(await started.text());
const { sessionId, computerId, messageId } = await started.json();
const query = `computerId=${encodeURIComponent(computerId)}`;
let replies = [];
for (;;) {
await new Promise((resolve) => setTimeout(resolve, 5000));
const session = await fetch(`${base}/sessions/${sessionId}?${query}`, {
headers,
});
if (!session.ok) continue;
const { status } = await session.json();
if (status !== "idle") continue;
const { messages } = await fetch(
`${base}/sessions/${sessionId}/messages?${query}&limit=100`,
{ headers },
).then((response) => response.json());
const promptIndex = messages.findIndex((message) => message.id === messageId);
replies =
promptIndex === -1
? []
: messages
.slice(promptIndex + 1)
.filter((message) => message.role === "assistant");
if (replies.length > 0) break;
}
console.log(replies);Related resources