Read the status before you read the stream.

An authentication or balance error is JSON, not SSE. Check the response first, then process bounded chunks until termination or disconnect.

curl without client buffering

SSE request

curl -N https://aiwave.live/v1/chat/completions \
  -H "Authorization: Bearer $AIWAVE_API_KEY" -H "Content-Type: application/json" \
  -d '{"model":"deepseek-v4-flash","stream":true,"messages":[{"role":"user","content":"Reply with OK"}]}'

Raw Python handling

httpx

import httpx, json, os

with httpx.stream("POST", "https://aiwave.live/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['AIWAVE_API_KEY']}"},
    json={"model": "deepseek-v4-flash", "stream": True, "messages": [{"role": "user", "content": "Reply with OK"}]},
    timeout=60.0) as response:
    response.raise_for_status()
    if "text/event-stream" not in response.headers.get("content-type", ""):
        raise RuntimeError("expected an SSE response")
    for line in response.iter_lines():
        if not line.startswith("data:"):
            continue
        data = line[5:].strip()
        if data == "[DONE]":
            break
        chunk = json.loads(data)
        # Accumulate content and any route-tested tool-call deltas here.

Wire contract

SignalMeaningHandler
HTTP 4xx/5xxNormal JSON error envelopeClassify before SSE parsing
Content-Type: text/event-streamStreaming bodyRead complete data events
data: {JSON}One chunkAccumulate content and tested tool deltas
data: [DONE]Normal terminationClose the reader
Network disconnectCompletion state unknownDo not repeat state-changing tool work blindly
Do not replay a request just to estimate tokens.

Save the request ID. Use verified final usage when the route returns it; otherwise reconcile the request ledger. A second generation is a second bill and may produce different output.