API Reference

The Broadcaster API gives your AI agents real-world communication channels — email, web, and more — with a single integration.

Base URL: https://api.broadcaster.aiv1

Quickstart

Get your agent sending and receiving email in under 60 seconds.

1. Install the SDK

Python
pip install broadcaster
TypeScript
npm install broadcaster

2. Create an inbox & send an email

Get your API key from the Dashboard and replace br_live_... below.

Python
from broadcaster import Broadcaster

client = Broadcaster(api_key="br_live_...")

agent = client.agents.create(
    name="Support",
    slug="support"
)

print(agent.email)  # support@broadcaster.ai

# Send an email
agent.send(
    to="user@example.com",
    subject="Hello!",
    body="Hello from my AI agent!"
)
TypeScript
import { Broadcaster } from "broadcaster";

const client = new Broadcaster({
  apiKey: "br_live_..."
});

const agent = await client.agents.create({
  name: "Support",
  slug: "support"
});

console.log(agent.email); // support@broadcaster.ai

// Send an email
await agent.send({
  to: "user@example.com",
  subject: "Hello!",
  body: "Hello from my AI agent!"
});

3. Receive emails

Set a webhook URL on your agent, and Broadcaster will POST inbound emails to your endpoint as structured JSON.

cURL — set webhook
curl -X PATCH https://api.broadcaster.ai/v1/agents/ag_abc123 \
  -H "Authorization: Bearer br_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "webhook_url": "https://myapp.com/webhook" }'

📋 Copy for Cursor / Claude

Copy this complete block into Cursor, Claude, or any AI coding assistant for a working Broadcaster integration with setup, error handling, and API reference.

Complete reference (Python)
"""
Broadcaster.ai — Complete API Reference for AI Coding Assistants
Copy this block into Cursor, Claude, or any AI coding assistant.

Base URL: https://api.broadcaster.ai/v1
Auth: Authorization: Bearer $BROADCASTER_API_KEY

=== AGENTS (Email Inboxes) ===
POST   /agents                          — Create agent (name, slug?, webhook_url?, client_id? for idempotency)
GET    /agents                          — List agents
GET    /agents/:id                      — Get agent
PATCH  /agents/:id                      — Update agent
DELETE /agents/:id                      — Delete agent

=== MESSAGES ===
POST   /agents/:id/messages/send        — Send email (to, subject, body, cc?, bcc?, reply_to?)
GET    /agents/:id/messages             — List messages (direction?, channel?, page?, per_page?)
GET    /messages/:id                    — Get message by ID
POST   /agents/:id/messages/:msgId/reply     — Reply (proper email threading)
POST   /agents/:id/messages/:msgId/reply-all — Reply all (all To/CC recipients)
POST   /agents/:id/messages/:msgId/forward   — Forward (to, body?)
POST   /agents/:id/messages/:msgId/labels    — Add labels (labels: string[])
DELETE /agents/:id/messages/:msgId/labels    — Remove labels

=== THREADS ===
GET    /agents/:id/threads              — List conversation threads (label?)
GET    /agents/:id/threads/:threadId    — Get thread with all messages

=== DRAFTS (Human-in-the-Loop) ===
POST   /agents/:id/drafts              — Create draft (to, subject?, body, in_reply_to_id?)
GET    /agents/:id/drafts              — List drafts (status?: draft|approved|sent|discarded|all)
GET    /agents/:id/drafts/:draftId     — Get draft
PATCH  /agents/:id/drafts/:draftId     — Update draft
POST   /agents/:id/drafts/:draftId/send — Approve and send
DELETE /agents/:id/drafts/:draftId     — Discard

=== ALLOW/BLOCK LISTS ===
POST   /agents/:id/lists               — Add entry (direction, list_type, entry, reason?)
GET    /agents/:id/lists               — List entries (direction?, list_type?)
DELETE /agents/:id/lists/:entryId      — Remove entry

=== SAFETY (Automatic on Inbound) ===
Every inbound email includes in metadata:
- injection_scan: { risk_level, detections[] } — prompt injection detection
- auth_flows: [{ type: otp|verification_link|magic_link|password_reset, value, confidence }]
High-risk emails auto-labeled "⚠️ injection-risk"

=== WEBHOOKS ===
Set webhook_url on agent creation. Payload:
{ event: "message.received", agent_id, message: { id, from, to, subject, body, attachments, labels, thread_id },
  safety: { is_suspicious, risk_level, detections }, auth_flows: [...] }
Verify: HMAC-SHA256 of body using webhook_secret (X-Broadcaster-Signature header)

=== WEBSOCKET ===
wss://api.broadcaster.ai/v1/agents/:id/listen?token=YOUR_KEY

=== ERRORS & LIMITS ===
400 validation, 401 unauthorized, 404 not found, 429 rate limited, 502 email delivery failed
Free: 1000 msgs/mo, 1 agent | Pro $9: 5000/mo, 10 agents | Scale $29: 25000/mo, 50 agents
"""
import os, requests

API = "https://api.broadcaster.ai/v1"
KEY = os.getenv("BROADCASTER_API_KEY")
H = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}

# Create agent
agent = requests.post(f"{API}/agents", json={"name": "Support", "slug": "support"}, headers=H).json()

# Send email with CC
requests.post(f"{API}/agents/{agent['id']}/messages/send", json={
    "to": "user@example.com", "cc": "manager@example.com",
    "subject": "Hello", "body": "From my AI agent", "channel": "email"
}, headers=H)

# Create draft for human review
draft = requests.post(f"{API}/agents/{agent['id']}/drafts", json={
    "to": "customer@example.com", "subject": "Re: Your inquiry",
    "body": "Thank you for reaching out..."
}, headers=H).json()

# Human approves → send
requests.post(f"{API}/agents/{agent['id']}/drafts/{draft['id']}/send", headers=H)

# List inbound with safety data
msgs = requests.get(f"{API}/agents/{agent['id']}/messages?direction=inbound", headers=H).json()
for msg in msgs["data"]:
    meta = msg.get("metadata", {})
    if meta.get("injection_scan", {}).get("is_suspicious"):
        print(f"⚠️ SUSPICIOUS: {msg['subject']} — {meta['injection_scan']['risk_level']}")
    if meta.get("auth_flows"):
        for af in meta["auth_flows"]:
            print(f"🔑 {af['type']}: {af['value']}")

Authentication

Authenticate API requests by including your API key in the Authorization header.

Authorization Header
curl https://api.broadcaster.ai/v1/agents \
  -H "Authorization: Bearer br_live_xxxxxxxxxxxxxxxx"

API Key Format

API keys are prefixed with br_live_ for production and br_test_ for sandbox environments. Keys are shown only once at account creation — store them securely.

Public Endpoints

Some endpoints are publicly accessible without authentication:

  • POST /v1/accounts — Create account
  • GET /v1/agents/by-slug/:slug — Public agent lookup
  • POST /v1/agents/:slug/contact — Contact form

WebSocket Authentication

The WebSocket endpoint at /v1/agents/:id/listen uses query parameter authentication since WebSocket connections don't support custom headers:

wss://api.broadcaster.ai/v1/agents/ag_abc123/listen?token=br_live_xxxxxxxx

Accounts

Agents

Messages

Threads

Safety & Auth Flows

Webhooks

WebSocket

Contact

Webhook Guide

When someone emails your agent or submits the web contact form, Broadcaster delivers the message to your webhook URL as an HTTP POST request.

Payload Format

Webhook Payload
{
  "event": "message.received",
  "agent_id": "ag_abc123",
  "message": {
    "id": "msg_abc456",
    "channel": "email",
    "from": "customer@gmail.com",
    "to": "support@broadcaster.ai",
    "subject": "Help with my order",
    "body": "I haven't received my package yet...",
    "body_html": "<p>I haven't received my package yet...</p>",
    "attachments": [],
    "received_at": "2026-03-26T10:30:00Z"
  },
  "timestamp": "2026-03-26T10:30:01Z",
  "signature": "sha256=xxxxxxxx"
}

Signature Verification

Every webhook request includes an HMAC-SHA256 signature in the signature field (and the X-Broadcaster-Signature header). Verify this signature using your agent's webhook_secret to ensure the request is authentic.

Node.js
import crypto from "crypto";

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(JSON.stringify(payload))
    .digest("hex");

  const sig = signature.replace("sha256=", "");

  return crypto.timingSafeEqual(
    Buffer.from(sig, "hex"),
    Buffer.from(expected, "hex")
  );
}

// In your webhook handler:
app.post("/webhook", (req, res) => {
  const signature = req.headers["x-broadcaster-signature"];
  const isValid = verifyWebhook(
    req.body,
    signature,
    process.env.WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(401).send("Invalid signature");
  }

  // Process the message
  const { message } = req.body;
  console.log(`New ${message.channel} from ${message.from}`);

  res.status(200).send("OK");
});
Python
import hmac
import hashlib
import json

def verify_webhook(payload, signature, secret):
    expected = hmac.new(
        secret.encode("utf-8"),
        json.dumps(payload).encode("utf-8"),
        hashlib.sha256
    ).hexdigest()

    sig = signature.replace("sha256=", "")

    return hmac.compare_digest(sig, expected)

# In your webhook handler (Flask example):
@app.route("/webhook", methods=["POST"])
def webhook():
    signature = request.headers.get(
        "X-Broadcaster-Signature"
    )
    is_valid = verify_webhook(
        request.json,
        signature,
        os.environ["WEBHOOK_SECRET"]
    )

    if not is_valid:
        return "Invalid signature", 401

    # Process the message
    message = request.json["message"]
    print(f"New {message['channel']} from {message['from']}")

    return "OK", 200

Retry Behavior

If your endpoint returns a non-2xx status code or the request times out, Broadcaster retries delivery up to 3 times with increasing delays:

Attempt 1
1s
Attempt 2
30s
Attempt 3
5m

After all 3 attempts fail, the delivery is marked as failed. You can inspect delivery attempts via the webhook delivery logs endpoint.

Best Practices

  • Always verify the HMAC signature before processing webhooks
  • Return a 200 response quickly — process messages asynchronously if needed
  • Use the message.id field for idempotency to handle potential duplicate deliveries
  • Use the test webhook endpoint to verify your setup during development

Errors

The API returns standard HTTP status codes. Error responses include a JSON body with error and code fields.

Error Response Format
{
  "error": "Agent not found",
  "code": "agent_not_found"
}
StatusCode
400validation_error
400invalid_request
400channel_not_enabled
401unauthorized
403forbidden
403plan_limit_agents
404agent_not_found
404message_not_found
409slug_taken
429rate_limited
429plan_limit_messages

Rate Limits

API requests are rate limited per account. Message sending is also subject to plan-based monthly quotas.

PlanMax AgentsMessages
Free11,000 / month
Pro105,000 / month
Scale5025,000 / month
EnterpriseUnlimitedUnlimited