# Streaming responses

Use Server-Sent Events for paraphrase rewrites, translation and summarization.

Send `stream: true` in the JSON body. `Accept: text/event-stream` is optional; the body flag selects streaming. Grammar, detector and citation requests require `stream: false`. Paraphrase `action: alternatives` always returns JSON, including when `stream: true` is sent.

```bash
curl --no-buffer --fail-with-body --silent --show-error \
  'https://metaphrase.msalman.com/api/v1/paraphrase' \
  -H "Authorization: Bearer $METAPHRASE_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"text":"Good writing helps people understand an idea.","mode":"standard","stream":true}'
```

A successful streaming response has HTTP 200 and `Content-Type: text/event-stream`. Event order:

1. `meta`: `{"request_id":"<UUID>","tool":"paraphrase"}`.
2. Zero or more `delta`: `{"text_delta":"a piece of output"}`. Append only `text_delta`; do not append the entire event JSON.
3. Exactly one terminal event: `done` with the **full ordinary JSON response envelope**, or `error` with the same `{"error":{"code","message","docs_url"}}` object used by JSON errors.

`done.result.text` is authoritative; replace your accumulated preview with it. A cache hit can send one delta containing the full result, followed by done with zero new usage. Local key-sentence summaries can also stream one complete result. Heartbeats are SSE comment lines beginning with `:` and must be ignored.

Validation/auth/quota/preflight failures occur before headers and use ordinary non-200 JSON. Once streaming begins, HTTP status cannot change; an `error` event may arrive after some deltas. If the connection closes without `done`, the result is incomplete. Preserve it as a partial preview, display the error, and do not cache it as a successful answer.

Use the SDK's streaming helper to handle UTF-8 boundaries and SSE framing:

```javascript
import { MetaPhrase } from '@metaphrase/sdk';
const client = new MetaPhrase({api_key:process.env.METAPHRASE_API_KEY});
let partial='';
try {
  for await (const event of client.stream('paraphrase',{text:'Good writing makes an idea easier to understand.',mode:'standard'})) {
    if(event.event==='delta'){partial+=event.data.text_delta;process.stdout.write(event.data.text_delta);}
    if(event.event==='done')console.log('\nCompleted:',event.data.result.text,event.data.usage);
  }
} catch(error) {
  console.error('Partial result:',partial);
  console.error(error.code,error.message,error.docs_url);
}
```

Install the SDK using [the SDK guide](https://metaphrase.msalman.com/docs/sdks.md). The Python helper is `client.stream('paraphrase', {'text': '...'})` and yields dictionaries with `event` and `data`. Both SDKs throw a `MetaPhraseError` on an error event or an incomplete stream. Browser `EventSource` cannot send a POST body or Bearer header; stream through your backend and use `fetch` streaming in the UI instead.

Abort the fetch/SDK stream when the user selects Stop. Cancellation can still incur upstream tokens; accepted calls still consume quota. Provider fallback happens only before any output is emitted, so two providers' output is never mixed. If you retry, start a separate result and replace the old preview rather than appending to it.
