Understanding the raw Server-Sent Events (SSE) format is essential for building custom streaming parsers, debugging, and working without the SDK.
Chat Completions SSE Format
Uses flat data: lines — no event: field:
Responses API SSE Format
Uses both event: and data: fields for typed events:
Events are separated by blank lines (\\n\\n). Chat Completions ends with data: [DONE]. The Responses API has no [DONE] sentinel — the response.completed event signals completion.
The full grammar in five lines
SSE is just newline-delimited frames. A frame is one or more lines of field: value, terminated by an empty line. The fields you'll actually see from OpenAI: data: (the JSON payload), : (a comment, used as keep-alive by some proxies — ignore). The terminator is the literal line data: [DONE].
Why this matters: if you're behind a corporate proxy or a CDN that injects keep-alive comments, hand-rolled parsers that only know about data: lines silently break. Either use iter_lines (which handles this) or write a parser that explicitly skips lines starting with :.