Skip to main content
Every agent task follows a predictable lifecycle. This page explains each phase, the available status values, and the patterns you can use to interact with a task at each stage.
The lifecycle, status values, and event stream below are identical across agent runtimes — a Codex task and a Claude task move through the same states and emit the same events. Whichever runtime the model (or agent override) selects is transparent to every endpoint on this page.

Lifecycle Overview

POST /api/v1/tasks


   { taskId, runId }          ← created (status: queued)


   Agent starts               ← status: running

        ├──► GET  /api/v1/tasks/:id/status          poll lightweight status

        ├──► GET  /api/v1/tasks/:id/logs/stream     live SSE log stream

        ├──► GET  /api/v1/agent/stream?runId=...    raw SSE stream

        ├──► POST /api/v1/tasks/:id/continue        send a follow-up prompt

        └──► PATCH /api/v1/tasks/:id               cancel the task


        Terminal state         ← completed | failed | cancelled | interrupted

Status Values

StatusDescriptionTerminal?
queuedTask is waiting to be picked up by an agentNo
runningAgent is actively executing the taskNo
completedTask finished successfully✅ Yes
failedTask encountered an unrecoverable error✅ Yes
cancelledTask was cancelled by the user✅ Yes
interruptedTask was interrupted (e.g. server restart)✅ Yes
Once a task reaches a terminal state it will not change again. Poll until you see one of the four terminal statuses.

Phase 1 — Create

Start a task with POST /api/v1/tasks. You receive a runId immediately — the agent begins executing asynchronously.
curl -X POST 'https://agent.blackbox.ai/api/v1/tasks' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "prompt": "Add a README in French",
    "repoUrl": "https://github.com/org/repo.git",
    "selectedBranch": "main"
  }'
{
  "taskId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "runId":  "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "chatId": "chat_def789ghi012",
  "agentCount": 1
}
Save the runId — you’ll use it for every subsequent operation.

Phase 2 — Monitor

You have two options for tracking progress:

Option A — Poll Status (lightweight)

Best for simple integrations. Call GET /api/v1/tasks/:id/status every few seconds:
const DONE = ["completed", "failed", "cancelled", "interrupted"];

while (true) {
  const res = await fetch(`/api/v1/tasks/${runId}/status`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  const s = await res.json();

  console.log(`${s.status} — ${s.progress}%`);
  if (DONE.includes(s.status)) break;

  await new Promise(r => setTimeout(r, 3000));
}
The progress field (0–100) is a linear estimate based on elapsed time.

Option B — Stream Logs (real-time)

Best for live UIs or CLI output. Connect to the SSE stream and receive events as they happen:
const response = await fetch(`/api/v1/tasks/${runId}/logs/stream`, {
  headers: { Authorization: `Bearer ${API_KEY}` },
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  for (const line of decoder.decode(value).split("\n")) {
    if (!line.startsWith("data: ")) continue;
    const event = JSON.parse(line.slice(6));

    if (event.type === "text-delta")   process.stdout.write(event.delta);
    if (event.type === "tool-call-start") console.log(`\nTool: ${event.toolName}`);
    if (event.type === "finish")       { console.log(`\nDone: ${event.status}`); break; }
  }
}

Phase 3 — Retrieve Results

Once completed, fetch the full task details including the conversation history and GitHub context:
curl 'https://agent.blackbox.ai/api/v1/tasks/RUN_ID' \
  -H 'Authorization: Bearer YOUR_API_KEY'
Key fields in the response:
FieldDescription
statusFinal status of the run
github.createdBranchBranch the agent pushed changes to
messagesFull conversation history
completedAtISO 8601 timestamp of completion
Extract the agent’s reply:
const data = await res.json();
const lastReply = data.messages.filter(m => m.role === "assistant").at(-1);
const text = lastReply?.parts?.find(p => p.type === "text")?.text ?? "";
console.log("Agent reply:", text);

Phase 4 — Continue (Optional)

Send a follow-up prompt to the same task. The agent receives the full conversation history as context and, if a GitHub repo was involved, continues from the branch it created:
curl -X POST 'https://agent.blackbox.ai/api/v1/tasks/RUN_ID/continue' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{ "prompt": "Now add unit tests for the new module" }'
The response contains a new runId for the follow-up run. Use it to track the continuation independently.

Cancel a Running Task

Send a PATCH request with action: "cancel" at any point while the task is queued or running:
curl -X PATCH 'https://agent.blackbox.ai/api/v1/tasks/RUN_ID' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{ "action": "cancel" }'
{ "success": true, "status": "cancelled", "message": "Task cancelled successfully" }
Cancelling a task that is already in a terminal state returns success: false.

Multi-Agent Tasks

When you pass selectedAgents with 2–5 entries, each agent gets its own runId. Track each run independently using the same endpoints described above.

Simple — Poll with Backoff

async function pollWithBackoff(runId, apiKey) {
  const DONE = ["completed", "failed", "cancelled", "interrupted"];
  let delay = 1000;

  while (true) {
    const res = await fetch(`/api/v1/tasks/${runId}/status`, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });
    const s = await res.json();
    if (DONE.includes(s.status)) return s;

    await new Promise(r => setTimeout(r, delay));
    delay = Math.min(delay * 2, 30_000); // cap at 30s
  }
}

Advanced — Stream + Continue

// 1. Create task
const res = await fetch("/api/v1/tasks", {
  method: "POST",
  headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ prompt: "Build a REST API" }),
});
const { runId } = await res.json();

// 2. Stream live output
const stream = await fetch(`/api/v1/tasks/${runId}/logs/stream`, {
  headers: { Authorization: `Bearer ${API_KEY}` },
});
const reader = stream.body.getReader();
const decoder = new TextDecoder();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  for (const line of decoder.decode(value).split("\n")) {
    if (!line.startsWith("data: ")) continue;
    const event = JSON.parse(line.slice(6));
    if (event.type === "text-delta") process.stdout.write(event.delta);
    if (event.type === "finish") break;
  }
}

// 3. Continue with a follow-up
const cont = await fetch(`/api/v1/tasks/${runId}/continue`, {
  method: "POST",
  headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ prompt: "Now add OpenAPI docs" }),
});
const { runId: newRunId } = await cont.json();

Create Task

POST /api/v1/tasks

Get Task Status

GET /api/v1/tasks/:id/status

Stream Task Logs

GET /api/v1/tasks/:id/logs/stream

Continue Task

POST /api/v1/tasks/:id/continue

Get Task

GET /api/v1/tasks/:id

Cancel Task

PATCH /api/v1/tasks/:id