CookbookStream with curl

Stream with curl

Streaming is the default on POST /v1/chat/completions: leave out stream (or set it to true) and the reply arrives as server-sent events.

See the raw events

curl -N https://app.syntic.ai/v1/chat/completions \
  -H "Authorization: Bearer $SYNTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Amara Quick",
    "messages": [{"role": "user", "content": "List four uses for a paperclip, one per line."}]
  }'

-N turns off curl’s output buffer, so each event prints the moment it arrives. You will see lines like:

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Hold"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":38,"completion_tokens":31,"total_tokens":69}}

data: [DONE]

jq with --unbuffered reads each event as it comes and prints the text pieces without line breaks between them:

curl -sN https://app.syntic.ai/v1/chat/completions \
  -H "Authorization: Bearer $SYNTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "Amara Quick", "messages": [{"role": "user", "content": "Write a haiku about tea."}]}' \
| sed -u -n 's/^data: //p' \
| grep --line-buffered -v '^\[DONE\]$' \
| jq --unbuffered -j '.choices[0].delta.content // empty, (if .error then "\n[stream error: \(.detail)]\n" else empty end)'
echo

How the pipeline works:

  1. sed -u -n 's/^data: //p' keeps only event lines and strips the data: prefix.
  2. grep -v '^\[DONE\]$' drops the end marker, which is not JSON.
  3. jq -j prints each text piece with no newline, and prints a notice if a stream_error event arrives.

Show the headers too

Response headers come before the first event. -D - prints them:

curl -sN -D - https://app.syntic.ai/v1/chat/completions \
  -H "Authorization: Bearer $SYNTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "Amara Quick", "messages": [{"role": "user", "content": "Hi"}]}' \
| grep -i -E '^(HTTP|x-syntic|content-type)'

Look for content-type: text/event-stream, x-syntic-request-id and x-syntic-billing-source.

When it fails

Errors found before streaming starts (bad key, rate limit, exhausted quota) return a normal JSON body and a non-200 status, not events. Add -f to make curl exit non-zero on those, or -w '%{http_code}' to print the status.

Was this page helpful?