angbot

Feed API

HTTP, WebSocket, SSE and webhooks. Base URL https://api.langbot.ai.

Auth: Authorization: Bearer lb_<token> (API token) or the lb_session cookie set by the web app. Public endpoints need no auth. Timestamps are ms epoch integers. IDs are evt_ / ev_ / src_ / sub_ / tok_ + ULID.

Public

GET /healthGET /v1/events/live                       # live + upcoming events with sources + marketsGET /v1/events/{event_id}GET /v1/events/{event_id}/transcript?since=<seq>GET /v1/markets?q=&venue=&status=open     # public metadataGET /v1/latency                           # per-source {source_id, kind, p50_lag_ms, p90_lag_ms, samples, last_ts}GET /v1/stats                             # sources this week, events today, p50 lag, installsGET /v1/calendar?days=7                   # upcoming events with sources, markets, speaker_keys and rights

Context

GET /v1/context/{ticker}                  # Builder and above

One call for an agent: the market row and rules, the settlement source, the latest order-book snapshot (yes_bid, yes_ask, bids and asks as [price, count]), the base rate for the market's own speaker and phrase, the live or upcoming event it belongs to (with rights), and recent mentions.

{  "market": { "ticker": "KXFEDMENTION-26OCT-TRANSITORY", "venue": "kalshi", "title": "Powell says “transitory”?", "phrases": ["transitory"], "status": "open" },  "rules_text": "Resolves YES if Chair Powell says “transitory” during the press conference…",  "settlement_source": "Federal Reserve press conference transcript",  "book": { "ticker": "KXFEDMENTION-26OCT-TRANSITORY", "ts": 1760133600000, "yes_bid": 11, "yes_ask": 13, "bids": [[11, 240], [10, 410]], "asks": [[13, 180], [14, 350]] },  "base_rates": { "speaker": "powell", "phrase": "transitory", "markets": 8, "yes_rate": 0.375, "avg_open_price": 22.5, "avg_close_price": 37.1, "mispricing": 15.0, "by_month": [] },  "event": { "id": "ev_fomc_oct_2026_presser", "status": "upcoming", "starts_at": 1760151600000, "speaker_keys": ["powell"], "rights": "public_domain" },  "mentions": [ { "phrase": "transitory", "speaker": { "label": "SPK_1", "name": "Jerome Powell", "confidence": 0.93 }, "event_id": "ev_fomc_sep_2026_presser", "source_id": "src_fomc_sep_2026_cspan", "t_spoken": 1758654123412, "t_detected": 1758654123498, "lag_vs_public_ms": 9100, "market_refs": ["KXFEDMENTION-26SEP-TRANSITORY"] } ]}

History

GET /v1/history/outcomes?speaker=&phrase=&series=&venue=&since=&until=&limit=&cursor=GET /v1/history/base-rates?speaker=&phrase=&series=&window_days=365GET /v1/history/speakers?q=GET /v1/history/mentions?speaker=&phrase=&since=&until=&limit=

/v1/calendar returns {"events": [...]}; outcomes {"items": [...], "next_cursor": string|null}; speakers {"speakers": [...]}; mentions {"mentions": [...]}. Outcomes are the venue's public settlement record and are paginated by next_cursor. Base rates return {markets, yes, no, void, yes_rate, by_month[], avg_open_price, avg_close_price, mispricing}; mispricing is avg(result − yes_price_open) in cents. Mentions are Langbot's own phrase_detected facts and never include raw. Field-level detail and worked examples are in History and base rates. Every plan gets the full record; each call counts one history query of the plan's daily allowance.

Stream

WS  /v1/stream?events=ev_a,ev_b&phrases=tariff,recession&types=phrase_detectedGET /v1/stream/sse   # same filters

The server sends {"type":"hello","seq":48213} first. You may send {"op":"subscribe","events":[...],"phrases":[...]} to change filters on an open socket.

Event

{  "id": "evt_01J9…",  "type": "phrase_detected",  "source_id": "src_nwb_q3_2026_dialin",  "event_id": "ev_nwb_q3_2026",  "market_refs": ["KXEARNINGSMENTIONNWB-26OCT-TARIFF"],  "phrase": "tariff",  "raw": "the bigger swing factor this quarter is tariff exposure",  "speaker": { "label": "SPK_1", "name": "CFO", "confidence": 0.91 },  "confidence": 0.97,  "t_spoken": 1760450523412,  "t_detected": 1760450523503,  "t_emitted": 1760450523507,  "lag_vs_public_ms": 18000,  "source_kind": "sip",  "seq": 48213,  "hash": "5d0e05c3…",  "prev_hash": "b6e26232…",  "raw_hash": "cd3e6e94…",  "chain_seq": 2}

type is one of phrase_detected, transcript_delta, speaker_change, event_started, event_ended, silence, source_status. source_status carries raw = JSON string with status (connecting / live / ended / error) and detail. lag_vs_public_ms is positive when Langbot heard the word before the public reference stream. The JSON Schema ships with both SDKs.

The last four fields are the event's receipt, set by the feed: hash is the sha256 of the canonical fact (including prev_hash), prev_hash is the hash of the previous event the feed emitted for the same source_id (null for the first), raw_hash is the sha256 of raw (survives redaction and retention; null when raw is null) and chain_seq is the 1-based position in the source's chain. They are null until the feed has seen the event. See Receipts.

Rights filter

Every public surface (/v1/stream, /v1/stream/sse, webhooks, /v1/events/{id}/transcript, MCP get_transcript) applies the source's rights. For public_domain and licensed sources events pass unchanged. For restricted and unknown sources (issuer earnings calls, broadcaster feeds) transcript_delta is not sent and raw on every other type is replaced by the matched phrase alone, so the example above would carry "raw": "tariff". The calendar reports rights per event so an agent knows in advance. See Legal.

Authenticated

POST   /v1/subscriptions        {event_id, phrases, webhook_url}GET    /v1/subscriptionsDELETE /v1/subscriptions/{id} POST   /v1/tokens               {name} → {token}   # shown onceGET    /v1/tokensDELETE /v1/tokens/{id} GET    /v1/me                   # {plan, plan_status, delays, limits, usage}POST   /v1/agent/heartbeat      # optional, from `langbot run`

/v1/me returns the plan key (free | pro | team | enterprise), plan_status (active | past_due | canceled, absent on Free), delays (the delay on the record for this account, in seconds), limits and usage keyed requests_today, tokens, subscriptions, ws_connections. Plan keys map to the names on the pricing page: pro is Builder, team is Standard, enterprise is Desk and Dedicated.

Receipts

GET    /v1/receipts/key                                   # public; also /.well-known/langbot-receipts.jsonGET    /v1/receipts/{evt_id}                              # public; {event, chain, checkpoint, rights, verified}POST   /v1/receipts/verify          {events:[...]}        # public, ≤ 500; {results:[{id, status, computed_hash, stored_hash, chain_ok, chain_seq, checkpoint}]}GET    /v1/receipts/checkpoints?source_id=&event_id=&limit=100   # publicGET    /v1/events/{event_id}/replay?format=json|jsonl&books=0|1&mine=0|1&since_seq=&source_id=&types=   # tokenPOST   /v1/receipts/attest          {evt_id, hash?, action, t_acted?}   # tokenGET    /v1/receipts/attestations?event_id=&evt_id=&since=&limit=100     # token, owner only

Lookup, verify, checkpoints and the key are public; replay and attestations need a token. Every plan can replay any recorded event; a replay counts one history query. Format, canonical form and the test vector are in Receipts.

Webhooks

Deliveries are POST with the JSON event as body and header X-Langbot-Signature: sha256=<hmac> computed over the raw body with your subscription secret. Retries with backoff for 5xx and timeouts.

Limits

Every feature is on every plan, Free included: webhooks, the full history, the fair-value and live models, Sim on any recorded event, MCP and every endpoint. Plans differ only in usage and speed.

Free (free)Builder (pro)Standard (team)Desk and Dedicated (enterprise)
Delay on the live record+60 s+10 s+2 sreal time, capped seats
API requests60 / min600 / min3,000 / minunlimited
Concurrent streams1520unlimited
Subscriptions5252001,000
API tokens520100500
Webhook endpoints15unlimitedunlimited
Webhook deliveries100 / day10,000 / dayunlimitedunlimited
History queries (full archive)500 / dayunlimitedunlimitedunlimited
Fair-value and live model calls100 / dayunlimitedunlimitedunlimited
Sim runs (any recorded event)20 / month100 / monthunlimitedunlimited

Days and months are UTC. A used-up allowance answers 429 with code: "quota_exceeded" and quota: {dimension, plan, used, limit, period, resets_at}; a held count at its cap (subscriptions, tokens, webhook endpoints) answers 402 with the same code. GET /v1/me returns quotas.<dimension> with used, limit, remaining and resets_at.