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.
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:
meta:{"request_id":"<UUID>","tool":"paraphrase"}.- Zero or more
delta:{"text_delta":"a piece of output"}. Append onlytext_delta; do not append the entire event JSON. - Exactly one terminal event:
donewith the full ordinary JSON response envelope, orerrorwith 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:
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. 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.