Skip to main content
Instead of polling or configuring webhooks, you can stream job status updates using Server-Sent Events (SSE). This is useful when you need real-time updates without a public webhook endpoint — for CLI tools, local scripts, or serverless functions.

Usage

curl -N https://api.bedrock.cv/jobs/job_01JABCD123/stream \
  -H "Authorization: Bearer sk_xxx"
The connection stays open and emits events as the job progresses:
event: status
data: {"job_id":"job_01JABCD123","status":"Queued","timestamp":"2024-01-15T10:00:00Z"}

event: status
data: {"job_id":"job_01JABCD123","status":"Started","timestamp":"2024-01-15T10:00:02Z"}

event: completed
data: {"job_id":"job_01JABCD123","status":"Completed","results":{...},"timestamp":"2024-01-15T10:01:30Z"}
The connection closes automatically when the job reaches a terminal state (Completed, Failed, or Canceled).

Event Types

EventDescription
statusJob status changed (Queued → Started, etc.)
progressProgress update for long-running jobs (e.g., “Processing sheet 3 of 12”)
completedJob finished successfully. Includes results.
failedJob encountered an error. Includes error.
canceledJob was canceled.

Progress Events

Long-running jobs (like drawing preprocessing) emit progress events:
event: progress
data: {"job_id":"job_01JABCD123","message":"Processing sheet 3 of 12","progress":0.25}

event: progress
data: {"job_id":"job_01JABCD123","message":"Processing sheet 6 of 12","progress":0.5}
The progress field is a number between 0 and 1. Not all job types emit progress events.

Already-Completed Jobs

If the job has already completed when you open the stream, you’ll receive a single terminal event and the connection closes:
event: completed
data: {"job_id":"job_01JABCD123","status":"Completed","results":{...},"timestamp":"2024-01-15T10:01:30Z"}

Example: Python

import requests

response = requests.get(
    "https://api.bedrock.cv/jobs/job_01JABCD123/stream",
    headers={"Authorization": "Bearer sk_xxx"},
    stream=True,
)

for line in response.iter_lines(decode_unicode=True):
    if line.startswith("data: "):
        data = json.loads(line[6:])
        print(f"[{data['status']}] {data.get('message', '')}")
        if data["status"] in ("Completed", "Failed", "Canceled"):
            break

Example: JavaScript

const source = new EventSource(
  "https://api.bedrock.cv/jobs/job_01JABCD123/stream",
  { headers: { Authorization: "Bearer sk_xxx" } }
);

source.addEventListener("completed", (event) => {
  const data = JSON.parse(event.data);
  console.log("Results:", data.results);
  source.close();
});

source.addEventListener("failed", (event) => {
  const data = JSON.parse(event.data);
  console.error("Error:", data.error);
  source.close();
});

Heartbeat

The server sends a comment line every 15 seconds to keep the connection alive:
: heartbeat

Connection Limits

Each API key can have up to 10 concurrent SSE connections. Opening an 11th connection returns 429 Too Many Requests.

When to Use What

MethodBest for
Streaming (SSE)CLI tools, local scripts, real-time UIs, serverless functions
PollingSimple integrations, environments that can’t hold connections open
WebhooksBackend services with public endpoints, event-driven architectures