diff --git a/fern/products/sdks/deep-dives/sse-metadata.mdx b/fern/products/sdks/deep-dives/sse-metadata.mdx
index 07007044ef..23ae5f6dc7 100644
--- a/fern/products/sdks/deep-dives/sse-metadata.mdx
+++ b/fern/products/sdks/deep-dives/sse-metadata.mdx
@@ -3,7 +3,7 @@ title: SSE metadata access
description: Access server-sent event metadata (event ID, event type, retry interval) in Fern-generated SDKs for stream resumption and protocol-level control.
---
-When your API uses [server-sent events](/learn/api-definitions/openapi/endpoints/sse#server-sent-events), iterating the generated SDK's streaming response yields parsed data objects. To also read the SSE protocol fields — event ID, event type, and retry interval — TypeScript and Go SDKs expose metadata-aware iteration, typically used to [resume a stream](#stream-resumption) by event ID.
+When your API uses [server-sent events](/learn/api-definitions/openapi/endpoints/sse#server-sent-events), iterating the generated SDK's streaming response yields parsed data objects. To also read the SSE protocol fields — event ID, event type, and retry interval — TypeScript, Python, and Go SDKs expose metadata-aware iteration, typically used to [resume a stream](#stream-resumption) by event ID.
## Metadata-aware iteration
@@ -22,6 +22,17 @@ Each event exposes the parsed data alongside its protocol fields. Default iterat
}
```
+
+ ```python
+ stream = client.plants.stream(query="fern")
+
+ for event in stream.with_metadata():
+ event.data # parsed response object (same type as default iteration)
+ event.id # SSE event ID (str | None)
+ event.event # SSE event type (str | None)
+ event.retry # SSE retry interval in ms (int | None)
+ ```
+
```go
stream := client.Plants.Stream(ctx, &PlantRequest{Query: "fern"})
@@ -44,8 +55,14 @@ Each event exposes the parsed data alongside its protocol fields. Default iterat
+Each stream owns the underlying HTTP response, and releases it differently per language:
+
+* **TypeScript**: the body is released when iteration ends and cancelled when you break out of the loop. An `abortSignal` in the request options stops the stream from outside.
+* **Python**: the stream is lazy, issuing the request on first iteration, and releases the response when it's exhausted, when iteration raises, on `close()`, or on exiting a `with` block. `AsyncStream` supports `async with` and is awaitable.
+* **Go**: the stream never closes the body on its own, so `defer stream.Close()` is required.
+
-`withMetadata()` requires TypeScript SDK generator version 3.73.0+, and `RecvEvent()` requires Go SDK generator version 1.32.0+.
+`withMetadata()` requires TypeScript SDK generator version 3.73.0+, and `RecvEvent()` requires Go SDK generator version 1.32.0+. In Python, `with_metadata()` requires generator version 5.29.0+ with [`stream_abstraction`](/learn/sdks/generators/python/configuration#stream_abstraction) enabled.
## Stream resumption
diff --git a/fern/products/sdks/generators/python/configuration.mdx b/fern/products/sdks/generators/python/configuration.mdx
index aed978aed4..69a9c68553 100644
--- a/fern/products/sdks/generators/python/configuration.mdx
+++ b/fern/products/sdks/generators/python/configuration.mdx
@@ -246,6 +246,17 @@ When enabled, the generated SDK resolves the version it reports in the `X-Fern-S
When enabled, skips code formatting (like black) on the generated Python code.
+
+When enabled, streaming endpoints return a `Stream[T]` (`AsyncStream[T]` for async clients) instead of a generator. Iterating yields the parsed payloads; `with_metadata()` yields them wrapped with the [server-sent event metadata](/learn/sdks/deep-dives/sse-metadata) fields `id`, `event`, and `retry`.
+
+```python
+for event in client.plants.stream(query="fern").with_metadata():
+ print(event.id, event.data)
+```
+
+This option changes the return type of streaming methods, so it remains opt-in until the next major generator version.
+
+
Sets the client timeout in seconds, or `infinity` to disable timeouts.