asyncapi: 3.0.0 info: title: HF Market Data — Filings stream version: 1.0.0 description: | WebSocket stream of SEC EDGAR filing events for the companies covered by `/v1/fundamentals`. One socket, one channel (`filings`), JSON text frames. Authentication by API key (`?api_key=` or `Authorization: Bearer `); keyless connections receive an `error` message and are closed with code **4001**. At most **5 concurrent connections per key** (6th → `STREAM_CONNECTION_LIMIT`, close **4029**). Heartbeat every **20 s**. The server keeps the last **1 000** events; `resume_token` (the last `seq` you received) replays what you missed. Each `filing` message delivered is charged **1 row** on your rows quota (reduced rate). contact: name: Simon-Pierre Boucher email: contact@spboucher.ai url: https://www.hfmarketdata.io license: name: Data: SEC EDGAR (public domain) — see terms url: https://www.hfmarketdata.io/docs/terms defaultContentType: application/json servers: production: host: www.hfmarketdata.io pathname: /v1/stream protocol: wss description: Production WebSocket endpoint. security: - $ref: '#/components/securitySchemes/apiKeyQuery' - $ref: '#/components/securitySchemes/apiKeyBearer' channels: stream: address: /v1/stream title: Single multiplexed socket description: | All messages flow on the one socket. Client → server: `subscribe`, `unsubscribe`, `ping`. Server → client: `hello`, `subscribed`, `unsubscribed`, `filing`, `heartbeat`, `pong`, `error`. messages: subscribe: $ref: '#/components/messages/subscribe' unsubscribe: $ref: '#/components/messages/unsubscribe' ping: $ref: '#/components/messages/ping' hello: $ref: '#/components/messages/hello' subscribed: $ref: '#/components/messages/subscribed' unsubscribed: $ref: '#/components/messages/unsubscribed' filing: $ref: '#/components/messages/filing' heartbeat: $ref: '#/components/messages/heartbeat' pong: $ref: '#/components/messages/pong' error: $ref: '#/components/messages/error' operations: subscribeFilings: action: send channel: $ref: '#/channels/stream' summary: Subscribe to the `filings` channel (optionally filtered by tickers / forms, resumable). messages: - $ref: '#/channels/stream/messages/subscribe' reply: channel: $ref: '#/channels/stream' messages: - $ref: '#/channels/stream/messages/subscribed' - $ref: '#/channels/stream/messages/error' unsubscribe: action: send channel: $ref: '#/channels/stream' messages: - $ref: '#/channels/stream/messages/unsubscribe' ping: action: send channel: $ref: '#/channels/stream' messages: - $ref: '#/channels/stream/messages/ping' reply: channel: $ref: '#/channels/stream' messages: - $ref: '#/channels/stream/messages/pong' receiveEvents: action: receive channel: $ref: '#/channels/stream' summary: Server pushes — the first frame is always `hello`. messages: - $ref: '#/channels/stream/messages/hello' - $ref: '#/channels/stream/messages/filing' - $ref: '#/channels/stream/messages/heartbeat' - $ref: '#/channels/stream/messages/error' components: securitySchemes: apiKeyQuery: type: httpApiKey name: api_key in: query description: '`wss://www.hfmarketdata.io/v1/stream?api_key=hfmd_live_…`' apiKeyBearer: type: http scheme: bearer bearerFormat: hfmd_live_… description: '`Authorization: Bearer hfmd_live_…` on the upgrade request.' messages: subscribe: name: subscribe title: Subscribe summary: Start (or replace) the subscription of this socket. payload: type: object required: [action] properties: action: const: subscribe channel: type: string enum: [filings] default: filings tickers: description: List of tickers (any share class) or the string `"all"`. oneOf: - type: array minItems: 1 items: { type: string } - const: all default: all forms: description: Form types to receive; omitted = all (10-K, 10-Q, 8-K, 20-F, 40-F, 6-K and amendments). type: array items: { type: string, examples: ['10-K', '10-Q', '8-K', '20-F', '10-K/A'] } resume_token: description: Last `seq` received; events with a greater `seq` still in the 1 000-event buffer are replayed first. type: integer examples: - name: Apple and Microsoft periodic reports, resumed payload: { action: subscribe, channel: filings, tickers: [AAPL, MSFT], forms: ['10-K', '10-Q'], resume_token: 1287 } unsubscribe: name: unsubscribe payload: type: object properties: action: { const: unsubscribe } ping: name: ping payload: type: object properties: action: { const: ping } hello: name: hello summary: First server frame after authentication. payload: type: object required: [type, seq, heartbeat_seconds] properties: type: { const: hello } seq: { type: integer, description: Current last sequence number (use it later as `resume_token`). } heartbeat_seconds: { type: number, const: 20 } max_connections_per_key: { type: integer, const: 5 } buffer: { type: integer, const: 1000 } ts: { type: string, format: date-time } subscribed: name: subscribed payload: type: object properties: type: { const: subscribed } channel: { const: filings } tickers: oneOf: [{ type: array, items: { type: string } }, { const: all }] forms: oneOf: [{ type: array, items: { type: string } }, { const: all }] resume_from: { type: integer } ts: { type: string, format: date-time } unsubscribed: name: unsubscribed payload: type: object properties: type: { const: unsubscribed } ts: { type: string, format: date-time } filing: name: filing title: Filing event summary: A new EDGAR filing of a covered company (published by the ingestion within ~2 minutes of EDGAR acceptance). payload: type: object required: [type, ticker, cik, form, filed_date, url, accn, seq] properties: type: { const: filing } ticker: { type: string, examples: [AAPL] } cik: { type: integer, examples: [320193] } form: { type: string, examples: ['10-Q'] } period: { type: [string, 'null'], format: date, description: Period of report. } filed_date: { type: string, format: date } url: { type: string, format: uri, description: Primary document on EDGAR. } accn: { type: string, description: Accession number. } seq: { type: integer, description: Monotonic sequence number (resume token). } summary: description: Standardized figures of the filing's own period (null for 8-K and when not yet normalized). Raw USD. type: [object, 'null'] properties: revenue: { type: [number, 'null'] } net_income: { type: [number, 'null'] } eps_diluted: { type: [number, 'null'] } total_assets: { type: [number, 'null'] } operating_cash_flow: { type: [number, 'null'] } fiscal_year: { type: integer } fiscal_quarter: { type: integer, description: 1–4, 0 = fiscal year } yoy: type: object description: Year-over-year growth versus the same fiscal period one year earlier (null when the base is missing or ≤ 0). properties: revenue: { type: [number, 'null'] } net_income: { type: [number, 'null'] } eps_diluted: { type: [number, 'null'] } examples: - name: Apple 10-Q for the quarter ended 2024-03-30 payload: type: filing ticker: AAPL cik: 320193 form: 10-Q period: '2024-03-30' filed_date: '2024-05-03' url: https://www.sec.gov/Archives/edgar/data/320193/000032019324000069/aapl-20240330.htm accn: 0000320193-24-000069 seq: 1288 summary: revenue: 90753000000 net_income: 23636000000 eps_diluted: 1.53 total_assets: 337411000000 operating_cash_flow: 22690000000 fiscal_year: 2024 fiscal_quarter: 2 yoy: { revenue: -0.0431, net_income: -0.0222, eps_diluted: 0.0066 } heartbeat: name: heartbeat summary: Sent every 20 s while the socket is open. payload: type: object properties: type: { const: heartbeat } ts: { type: string, format: date-time } seq: { type: integer } pong: name: pong payload: type: object properties: type: { const: pong } ts: { type: string, format: date-time } seq: { type: integer } error: name: error summary: Same envelope fields as the REST errors (`code`, `message`, `docs`). Fatal errors are followed by a close frame. payload: type: object required: [type, code, message, docs] properties: type: { const: error } code: type: string enum: [AUTH_REQUIRED, STREAM_CONNECTION_LIMIT, VALIDATION_ERROR, NOT_FOUND] message: { type: string } docs: { type: string, format: uri } limit: { type: integer, description: Present on STREAM_CONNECTION_LIMIT. } examples: - name: keyless connection (then close 4001) payload: type: error code: AUTH_REQUIRED message: 'A valid API key is required for the stream: pass ?api_key=… or Authorization: Bearer ….' docs: https://www.hfmarketdata.io/docs/errors#auth_required x-close-codes: '4001': AUTH_REQUIRED — no or invalid API key '4029': STREAM_CONNECTION_LIMIT — more than 5 concurrent sockets for this key '4400': protocol error