Consume Alpaca Broker API real-time event streams over Server-Sent Events (SSE) — account status, journal, transfer/funding, trade, and non-trade-activity events — reliably. Covers connection, auth, replay cursors (since/since_id), heartbeats, reconnection/backoff, ordering, and idempotent processing. Use when building an event consumer for Alpaca lifecycle events in any language.
npx skills add https://github.com/alpacahq/alpaca-skills --skill alpaca-broker-sse-events
Alpaca pushes brokerage lifecycle events over Server-Sent Events: a long-lived HTTP GET that streams text/event-stream. This is *not* the market-data WebSocket (alpaca-broker-market-data) — different transport, different auth, different reliability model.
> Read alpaca-broker-integration first. SSE uses the Broker API host + HTTP Basic auth (same credential as Broker REST).
https://docs.alpaca.markets/docs/sse-eventsalpaca-docs MCP → search "SSE Events", then fetch us/sse-eventsSSE is plain HTTP. You don't need a special client: open a GET, keep the connection open, and read the body line-by-line. Each event is a data: line containing a JSON object. It is replayable — you can ask for events from a point in the past and seamlessly catch up to live, which makes it far better than naive polling for lifecycle state.
| Stream | Path | Carries |
|--------|------|---------|
| Account status | GET /v1/events/accounts/status | Account-property changes: status/crypto_status (SUBMITTED→ACTIVE, ACTION_REQUIRED, REJECTED), plus kyc_results, account_blocked, trading_blocked, cash_interest, options |
| Journal status | GET /v2/events/journals/status | JNLC/JNLS lifecycle (queued→executed, correct…) |
| Funding/transfer status | GET /v2/events/funding/status | Unified: Transfer, BankRelationship, WireBank, FundingWallet entities (switch on entity_type) |
| Trade updates | GET /v2/events/trades | Order events in the event field: new, fill, partial_fill, canceled, rejected, held, trade_bust, trade_correct… (richer than order status) |
| Non-trade activities | GET /v1/events/nta | Dividends, interest, fees, splits, ACATs, cash disbursements. entry_type e.g. JNLC/FEE/INT/DIVNRA/CSD; status ∈ executed/correct/canceled |
> Paths & versions are NOT uniform — verify each. This is exactly the kind of cross-stream inconsistency Alpaca's docs under-communicate:
> - /v2 streams (trades, journals/status, funding/status) use a ULID event_id directly; /v1/events/trades and /v1/events/journals/status are *legacy* (existing partners only — migrate to v2). /v2/events/trades was previously /v2beta1, now redirected.
> - /v1 streams (accounts/status, nta) are current, not deprecated — there is no v2 yet. Each event carries both an integer event_id *and* a ULID event_ulid.
>
> Every event carries at (timestamp), account_id, and status_from/status_to (account/journal/funding) or event+order (trades).
GET /v2/events/journals/status?since_id=<last-ulid-you-saw> HTTP/1.1
Host: broker-api.alpaca.markets
Authorization: Basic <base64(key:secret)>
Accept: text/event-stream
Read the response stream and parse data: {…} frames as they arrive. In most languages an off-the-shelf EventSource/SSE client works — just make sure it lets you set the Authorization header on the initial request (the browser EventSource API famously does *not*; use a server-side SSE library instead).
Every stream supports point-in-time replay:
| Param | Meaning |
|-------|---------|
| since / until | Date or RFC3339 timestamps. URL-encode + in offsets as %2B. |
| since_id / until_id | ID cursors. On v2 streams the ID *is* a ULID. On v1 streams it's the integer event_id. |
| since_ulid / until_ulid | v1 streams only (accounts, nta) — ULID-based cursors, since v1 events carry both an int event_id and a event_ulid. |
Rules: since is required if until is set; since_id required if until_id set (same for since_ulid/until_ulid); you can't mix since, since_id, and since_ulid. Without any since cursor, no history is returned — you only get live pushes from now on. Reaching the until bound ends the stream with a 200.
This is the single most important reliability lesson: persist the ID of the last event you *successfully processed*. On every (re)connect, pass it as your since cursor (since_id on v2; since_ulid or since_id on v1) so Alpaca replays anything you missed during the gap. A consumer that reconnects without a cursor silently drops every event that occurred while it was down.
Within a millisecond, ULIDs contain a random component, so two events in the same millisecond can sort either way. Alpaca's own guidance: for reconciliation, restart the stream from a since a few minutes before your last event and rely on idempotent processing to absorb the overlap. Don't assume strict total ordering — assume *approximate* ordering plus dedup.
SSE connections drop — networks, load balancers, deploys, and Alpaca-side resets all happen. A production consumer needs:
lastMessageAt on every frame; if the stream is silent past a threshold (e.g. 5 min), proactively tear down and reconnect — a dead socket often looks "open."since_id = last processed event (see §4).> Note: OpenAPI can't fully model SSE, so generated API clients often hang on these endpoints (waiting for a response that never ends). Use a real streaming HTTP/SSE client, not a codegen'd one.
The robust shape for each event:
parse → persist a raw event snapshot (keyed on event_id, skip-if-exists)
→ match the local record by Alpaca ID (account_id / journal_id / order_id / transfer_id)
→ update local state under a row lock / guarded by current status
→ fire side effects (notifications, downstream transfers)
→ advance the stored cursor to this event_id
event_id. Insert the raw event with an upsert/skip-duplicate on event_id. A duplicate (from replay or an at-least-once redelivery) is then a no-op. This is your dedup boundary.SELECT … FOR UPDATE or equivalent) when mutating a transfer/order so two events for the same record can't race.status_to == ACTIVE. Reject sandbox/paper account IDs in live handlers.new/accepted/pending_new are pre-fill; update local order state on fill/partial_fill/canceled/rejected. Invalidate any cached portfolio/holdings on fills.executed isn't final and correct spawns a *new* journal ID (see alpaca-broker-journals). Idempotency + ID-keyed snapshots absorb both.entity_type. Funding-wallet *per-transfer* status may still need polling (alpaca-broker-funding-transfers).Even a perfect consumer can miss events (extended downtime beyond retention, a bug, an un-handled type). Always pair SSE with a periodic reconciliation/heal pass that re-pulls authoritative state (activities, journals, transfers) from Alpaca and upserts it. SSE is for low latency; reconciliation is for correctness. See alpaca-broker-reconciliation-idempotency.
Related skills: correctness backstop → alpaca-broker-reconciliation-idempotency; dedup/idempotency mechanics → alpaca-broker-reconciliation-idempotency; backoff details → alpaca-broker-rate-limits-resilience; market-data streaming (WS, not SSE) → alpaca-broker-market-data.
Integration with protocols.io API for managing scientific protocols. This skill should be used when working with protocols.io to search, create, update, or publish protocols; manage protocol steps and materials; handle discussions and comments; organize workspaces; upload and manage files; or integrate protocols.io functionality into workflows. Applicable for protocol discovery, collaborative protocol development, experiment tracking, lab protocol management, and scientific documentation.
Analyzes job descriptions and generates tailored resumes that highlight relevant experience, skills, and achievements to maximize interview chances
Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw.
Build and distribute Expo development clients locally or via TestFlight
Use when you have a written implementation plan to execute in a separate session with review checkpoints
Data structure for annotated matrices in single-cell analysis. Use when working with .h5ad files or integrating with the scverse ecosystem. This is the data format skill—for analysis workflows use scanpy; for probabilistic models use scvi-tools; for population-scale queries use cellxgene-census.
Benchling R&D platform integration. Access registry (DNA, proteins), inventory, ELN entries, workflows via API, build Benchling Apps, query Data Warehouse, for lab data management automation.
Comprehensive molecular biology toolkit. Use for sequence manipulation, file parsing (FASTA/GenBank/PDB), phylogenetics, and programmatic NCBI/PubMed access (Bio.Entrez). Best for batch processing, custom bioinformatics pipelines, BLAST automation. For quick lookups use gget; for multi-service integration use bioservices.
Take alpacahq/alpaca-broker-sse-events from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.