> ## Documentation Index
> Fetch the complete documentation index at: https://docs.locusmedical.fr/llms.txt
> Use this file to discover all available pages before exploring further.

# retrieve/stream

> POST /v2/retrieve/stream — the same answer, streamed step by step as NDJSON.

`POST /v2/retrieve/stream` takes the **same request body** as
[`/v2/retrieve`](/en/capabilities/retrieve) and returns the **same payload** —
but as it happens, one JSON line per step that actually completed.

This is what lets a UI show the **real** progress of a retrieval instead of a bar
that invents it. An answer chains several heavy calls; a step that stays silent
through them is indistinguishable from a step that is stuck.

```
Content-Type: application/x-ndjson
```

Each line is a complete JSON object, separated by `\n`. There is no reconnection
to handle: `fetch` plus a stream reader is enough.

## The lines

| `step`         | Emitted when                                                                     |
| -------------- | -------------------------------------------------------------------------------- |
| `query_maker`  | The question is classified and reformulated.                                     |
| `retrieval`    | Both paths have returned their units.                                            |
| `deliberation` | The second reading finished (full trace).                                        |
| `answer`       | The answer is written.                                                           |
| `drugs`        | Drug cards are attached.                                                         |
| `done`         | **Terminal line.** `payload` carries the full body, identical to `/v2/retrieve`. |
| `error`        | **Terminal line.** `detail` says what gave out.                                  |

With `deliberate: true`, the reflexive loop also streams each of its rounds
**without waiting for its verdict**:

| `step`               | What it carries                                                                                                         |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `deliberation_judge` | `index`, `saw` (what the judge had in front of it), `sufficient`, `checks`, `gaps`, the `probe` it decided on, `asked`. |
| `deliberation_probe` | `index`, `modality`, `query`, `seeds`, `rationale`, `gained`, `gained_ids`.                                             |

Without them, the step stays silent through three heavy calls and two retrievals.

<Note>
  A dependency failure can no longer raise an HTTP error here: the stream has
  already started, so it arrives as a terminal `error` line. The status is `200`
  from the first line — read the stream's content, not the code.
</Note>

## Reading the stream

<CodeGroup>
  ```typescript TypeScript theme={null}
  const resp = await fetch("https://core.locusmedical.fr/v2/retrieve/stream", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.LOCUS_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query: "antibioprophylaxie chirurgie colorectale" }),
  });

  const reader = resp.body!.getReader();
  const decoder = new TextDecoder();
  let buffer = "";

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });

    // A complete line is one object. The last one may be partial: keep it.
    const lines = buffer.split("\n");
    buffer = lines.pop() ?? "";

    for (const line of lines) {
      if (!line.trim()) continue;
      const event = JSON.parse(line);
      if (event.step === "done") console.log(event.payload.answer);
      else if (event.step === "error") throw new Error(event.detail);
      else showProgress(event.step);
    }
  }
  ```

  ```python Python theme={null}
  import httpx, json

  with httpx.stream(
      "POST",
      "https://core.locusmedical.fr/v2/retrieve/stream",
      headers={"Authorization": f"Bearer {LOCUS_API_KEY}"},
      json={"query": "antibioprophylaxie chirurgie colorectale"},
      timeout=180,
  ) as r:
      r.raise_for_status()
      for line in r.iter_lines():
          if not line:
              continue
          event = json.loads(line)
          if event["step"] == "done":
              print(event["payload"]["answer"])
          elif event["step"] == "error":
              raise RuntimeError(event["detail"])
          else:
              print("…", event["step"])
  ```

  ```bash cURL theme={null}
  curl -N -X POST https://core.locusmedical.fr/v2/retrieve/stream \
    -H "Authorization: Bearer $LOCUS_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"query": "antibioprophylaxie chirurgie colorectale"}'
  ```
</CodeGroup>

<Warning>
  Buffer the tail. A network chunk does not land on a line boundary: naively
  splitting on `\n` without keeping the remainder cuts a JSON object in half and
  fails the parse at the mercy of the load.
</Warning>
