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
}
}
}
}
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"
}
Logs & Streaming
Stream Task Logs
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.
GET
/
api
/
v1
/
tasks
/
{runId}
/
logs
/
stream
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
}
}
}
}
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"
}
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:- Go to app.blackbox.ai/agent-api and click Get an API Key (requires a Pro subscription)
- Once provisioning completes, you will be redirected to your Dashboard
- From the Dashboard, create an API key to use with all Agent API requests
sk-xxxxxxxxxxxxxxxxxxxxxx
Headers
string
required
API Key of the form
Bearer <api_key>.Example: Bearer sk_b41b647ffbfed27f616560Path Parameters
string
required
The unique run identifier returned when the task was created.Example:
a1b2c3d4-e5f6-7890-abcd-ef1234567890Query Parameters
boolean
default:"true"
Whether to include
text-delta events (individual text chunks). Set to false for a cleaner stream with only structural events.Default: trueResponse Format
The endpoint returnsContent-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
event
Beginning of a new text block from the agent.Fields:
id — message identifierevent
Incremental text chunk from the agent.Fields:
id, delta — text chunk stringevent
Agent started a tool call.Fields:
toolCallId, toolNameevent
Tool call input is ready.Fields:
toolCallId, toolName, input — tool input objectevent
Tool call result is available.Fields:
toolCallId, toolName, output — tool output objectevent
Files produced by the task.Fields:
files — array of file objectsevent
Task completed (stream closes after this).Fields:
runId, statusevent
Task failed (stream closes after this).Fields:
errorTextcurl -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
}
}
}
}
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 |