Stream Task Logs

GEThttps://agent.blackbox.ai/api/v1/tasks/{runId}/logs/stream

Stream task execution logs in real-time using Server-Sent Events (SSE). Live runs stream from the in-memory buffer; completed runs replay from persisted message parts.

This endpoint provides a real-time SSE stream of task execution events. For live tasks it subscribes to the in-memory event buffer and pushes events as they arrive. For completed tasks it replays all persisted events in a single burst and closes the stream.

The event type values are the same regardless of agent runtime — Claude and Codex tasks emit an identical contract (session-init, text-delta, tool-call-start, tool-input-available, tool-output-available, result, …). See the full event table.

Authentication

To use this API, you need a BLACKBOX API Key. Follow these steps to get your API key:

  1. Go to app.blackbox.ai/agent-api and click Get an API Key (requires a Pro subscription)
  2. Once provisioning completes, you will be redirected to your Dashboard
  3. From the Dashboard, create an API key to use with all Agent API requests

Your API key will be in the format: sk-xxxxxxxxxxxxxxxxxxxxxx

Headers

Authorizationstringrequired

API Key of the form Bearer <api_key>.

Example: Bearer sk_b41b647ffbfed27f616560

Path Parameters

runIdstringrequired

The unique run identifier returned when the task was created.

Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890

Query Parameters

includeDeltasbooleandefault: true

Whether to include text-delta events (individual text chunks). Set to false for a cleaner stream with only structural events.

Default: true

Response Format

The endpoint returns Content-Type: text/event-stream. Each event is a JSON object on a data: line:

data: {"type":"text-start","id":"msg_abc123"}

data: {"type":"text-delta","id":"msg_abc123","delta":"Hello, "}

data: {"type":"finish","runId":"...","status":"completed"}

Event Types

text-startevent

Beginning of a new text block from the agent.

Fields: id — message identifier

text-deltaevent

Incremental text chunk from the agent.

Fields: id, delta — text chunk string

tool-call-startevent

Agent started a tool call.

Fields: toolCallId, toolName

tool-input-availableevent

Tool call input is ready.

Fields: toolCallId, toolName, input — tool input object

tool-output-availableevent

Tool call result is available.

Fields: toolCallId, toolName, output — tool output object

task-filesevent

Files produced by the task.

Fields: files — array of file objects

finishevent

Task completed (stream closes after this).

Fields: runId, status

errorevent

Task failed (stream closes after this).

Fields: errorText

Request Example
curl -N 'https://agent.blackbox.ai/api/v1/tasks/a1b2c3d4-e5f6-7890-abcd-ef1234567890/logs/stream' \
  -H 'Authorization: Bearer YOUR_API_KEY'
const API_KEY = "YOUR_API_KEY";
const RUN_ID = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";

const response = await fetch(
  `https://agent.blackbox.ai/api/v1/tasks/${RUN_ID}/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;

  const chunk = decoder.decode(value);
  for (const line of chunk.split("\n")) {
    if (line.startsWith("data: ")) {
      const event = JSON.parse(line.slice(6));
      console.log(event.type, event);

      if (event.type === "finish" || event.type === "error") break;
    }
  }
}
// Note: Browser EventSource doesn't support custom headers.
// Pass the API key as a query param or use a server-side proxy.
const RUN_ID = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
const url = `https://agent.blackbox.ai/api/v1/tasks/${RUN_ID}/logs/stream`;

const es = new EventSource(url);

es.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.type === "text-delta") {
    process.stdout.write(data.delta);
  } else if (data.type === "finish") {
    console.log("\nDone:", data.status);
    es.close();
  } else if (data.type === "error") {
    console.error("Error:", data.errorText);
    es.close();
  }
};

es.onerror = () => es.close();
import requests
import json

API_KEY = "YOUR_API_KEY"
RUN_ID = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

response = requests.get(
    f"https://agent.blackbox.ai/api/v1/tasks/{RUN_ID}/logs/stream",
    headers={"Authorization": f"Bearer {API_KEY}"},
    stream=True,
)

for line in response.iter_lines():
    if line and line.startswith(b"data: "):
        event = json.loads(line[6:])
        print(event["type"], event)

        if event["type"] in ("finish", "error"):
            break
package main

import (
    "bufio"
    "encoding/json"
    "fmt"
    "net/http"
    "strings"
)

func main() {
    apiKey := "YOUR_API_KEY"
    runId := "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
    url := fmt.Sprintf("https://agent.blackbox.ai/api/v1/tasks/%s/logs/stream", runId)

    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Set("Authorization", "Bearer "+apiKey)

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    scanner := bufio.NewScanner(resp.Body)
    for scanner.Scan() {
        line := scanner.Text()
        if strings.HasPrefix(line, "data: ") {
            var event map[string]interface{}
            json.Unmarshal([]byte(line[6:]), &event)
            fmt.Println(event["type"], event)

            if event["type"] == "finish" || event["type"] == "error" {
                break
            }
        }
    }
}
Response Example
data: {"type":"text-start","id":"msg_abc123"}

data: {"type":"text-delta","id":"msg_abc123","delta":"I'll start by cloning the repository..."}

data: {"type":"tool-call-start","toolCallId":"tc_001","toolName":"bash"}

data: {"type":"tool-input-available","toolCallId":"tc_001","toolName":"bash","input":{"command":"git clone https://github.com/org/repo.git /vercel/sandbox"}}

data: {"type":"tool-output-available","toolCallId":"tc_001","toolName":"bash","output":{"stdout":"Cloning into '/vercel/sandbox'...\ndone.","exitCode":0}}

data: {"type":"text-delta","id":"msg_abc123","delta":"Repository cloned successfully. Now adding the README..."}

data: {"type":"finish","runId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","status":"completed"}
{
  "status": "queued",
  "error": null,
  "message": "No logs available to stream. Task may not have started or logs were cleared."
}
{
  "error": "Unauthorized"
}

Error Codes

Status Code Error Description
200 Success SSE stream established
401 Unauthorized Invalid or missing API key
403 Forbidden Task belongs to a different user
404 Not Found Task not found
409 Conflict No logs available to stream
500 Internal Server Error Failed to start stream