Quick Start

LLM API streaming and SSE integration guide

Distinguish SSE terminal events, missing usage and output truncation across Chat Completions, Responses and Messages, with curl, Python and Node.js examples.

Updated November 4, 2026Checked 2026-07-12Estimated reading time: 10 minutesApplies to Chat Completions streaming API
Configuration fields were checked against public documentation. Models, prices, and capabilities can change; verify current values in the console and live API responses.

Streaming delivers incremental content before generation finishes; it does not make the model itself faster. It can reduce perceived waiting time, but requires careful handling of SSE parsing, proxy buffering, connection interruption and usage statistics and related issues.

Parse Link GPT, Claude and Gemini streams according to the endpoint in use. Chat Completions chunks cannot simply be passed to a Messages or Responses parser. Save raw event types and completion events before attributing a failure to the network or parser.

A disconnected stream does not imply zero usage. Check the Link usage log for failed and retried requests, and whether wallet fallback applies after the daily allowance runs out. Avoid unlimited retries of long outputs.

Review Link funding and monthly-plan rules

Is the SSE stream complete? Check the endpoint, not the model brand

HTTP 200, the first text fragment and connection closure are distinct signals; none alone proves task completion. Identify the final request path before using this table. A GPT, Claude or Gemini name does not identify the protocol. Gemini via Chat Completions follows that protocol; native endpoints are outside this table's scope.

Request endpoint Terminal evidence to record What still needs checking
/v1/chat/completions data: [DONE] and each choice's finish_reason stop ends generation; length reaches an output limit; tool_calls requires further tool handling, not a completed business task
/v1/responses response.completed, response.failed or response.incomplete response.output_text.done ends one text part; failed and incomplete must not be recorded as complete success
/v1/messages message_stop and the stop_reason in message_delta content_block_stop ends one block; tool_use needs a tool result, and in-stream errors require separate handling

These criteria were checked against the official protocol references below on November 4, 2026. They are not a claim that every Link model has passed testing. A completed response does not by itself prove correct tool execution, file contents or an entire agent task.

Two endings that are easy to misclassify

These simplified teaching excerpts are not live Link request logs. The first reaches an output limit despite receiving [DONE]. The second reports an incomplete response. Receiving a text delta alone does not establish success.

data: {"choices":[{"index":0,"delta":{},"finish_reason":"length"}]}

data: [DONE]
event: response.incomplete
data: {"type":"response.incomplete","response":{"status":"incomplete","incomplete_details":{"reason":"max_output_tokens"}}}

If the connection closes before any terminal event, record an interruption or unknown outcome, then inspect client cancellation, timeouts and server logs. Do not fabricate a stop or [DONE] marker to complete a broken stream, or automatically replay a tool that may already have run.

Check before you start

Complete three confirmations first:

  1. Use non-streaming requests to verify that the API Key, model ID, and underlying API are working properly.
  2. Confirm that the target model and API support streaming output.
  3. Verify that clients, reverse proxies, and CDNs do not cache or merge event streams.

If non-streaming requests also fail, first check for 401, model not found or API paths. Do not start debugging directly from SSE.

Configuration steps

1. Use curl to view the original event stream

curl -N --include --connect-timeout 10 --max-time 120 https://www.aifast.link/v1/chat/completions \
  -H "Authorization: Bearer ${AIFAST_API_KEY:?Set AIFAST_API_KEY locally before running}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "YOUR_MODEL_ID",
    "stream": true,
    "messages": [
      {"role": "user", "content": "Explain SSE in three points."}
    ]
  }'

-N Will turn off curl's output buffering. Under normal circumstances, the terminal will have multiple consecutive data: chunks of data instead of waiting for the entire content to be generated and displayed at once.

This command sends a real request to Link and may incur charges. The 120-second limit is a demonstration deadline, not a service SLA. Curl aborts when it is reached; that alone does not establish an upstream failure. Remove keys, cookies, user input and sensitive response content before sharing logs.

2. Python SDK streaming reading

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AIFAST_API_KEY"],
    base_url="https://www.aifast.link/v1",
)

stream = client.chat.completions.create(
    model="YOUR_MODEL_ID",
    stream=True,
    messages=[
        {"role": "user", "content": "List three API pre-launch checks."}
    ],
)

for chunk in stream:
    if not chunk.choices:
        continue
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)

Don't assume that every chunk of data has text. Tool calls, role information, end reasons or compatibility layer events may appear in different fields. The formal code needs to first determine whether the fields exist.

3. Node.js SDK streaming reading

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.AIFAST_API_KEY,
  baseURL: "https://www.aifast.link/v1",
});

const stream = await client.chat.completions.create({
  model: "YOUR_MODEL_ID",
  stream: true,
  messages: [
    { role: "user", content: "Explain two common streaming failures." },
  ],
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

4. Record completeness rather than just display text

The production environment records at least:

Field Purpose
Request start time Calculate total time
First response byte timestamp Measure TTFB; the first bytes may only contain headers or a heartbeat
First non-empty text delta timestamp Measure client-observed time to first text; exclude role-only and empty deltas
Last event or stop reason Check whether the response ended completely
Request ID Locate requests when contacting support
Accumulated content length Identify interruptions
Usage and final charges Record client statistics and billing separately; missing statistics do not mean zero usage

How do I get streaming usage in Chat Completions?

Where the endpoint supports it, add stream_options: {"include_usage": true} to a stream: true request. The official protocol sends a statistics chunk before [DONE], with choices: []. Read usage before skipping empty choices. The minimal SDK examples above display text only; they do not collect billing data.

Do not copy this option into Responses or Messages requests. If a compatible endpoint rejects it, verify that endpoint's support rather than ignoring the error or inventing usage. When final statistics are missing after an interruption, check Link usage logs.

FAQ

The server is streaming, but the web page is still displayed at once

First, use curl -N to check the origin server. If chunks appear in the terminal, inspect your backend framework, reverse proxy and frontend reader. Check response buffering and whether the client reads incrementally from response.body.

The output suddenly stops halfway

Record the last event, stop reason and request ID. Possible causes include read timeouts, network interruptions, proxy idle timeouts, browser cancellation and upstream generation failures. Do not store partial content as a successful result.

Why there is no usage for streaming requests

Some protocols only return full usage in the last data block. If the connection is interrupted early, the client may not get the final statistics. The accounting reconciliation is based on the console and server records, and cannot only rely on the data blocks received by the front end.

Next step

Test short text, long text, Chinese, multi-byte characters, active cancellation, network disconnection and proxy timeout respectively. Before going online, the maximum task duration, disconnection status, and user-visible retry entry should also be set for streaming requests.

For an existing disconnection, use the 502 and stream-disconnection decision table to choose the next check. Once the endpoint passes, use the API Cost Calculator to budget for actual usage and billed retries. No key is required, and demonstration values are not Link prices.

FAQ

Does HTTP 200 or visible text mean an SSE request succeeded?

No. HTTP 200 only shows that the response has started. Check the protocol's terminal event, stop reason and task output. A disconnection after partial text, or reaching an output limit, is not a complete business result.

Must Responses and Messages also wait for data: [DONE]?

Do not mix protocol markers. Check [DONE] and finish_reason for Chat Completions; distinguish response.completed, response.failed and response.incomplete for Responses; check message_stop and stop_reason for Messages. Ending one content block does not end the whole message.

Does missing streaming usage mean there was no charge?

No. Where supported, Chat Completions can request stream_options.include_usage, but an interruption can prevent the final statistics from arriving. Missing client-side usage does not mean zero consumption. Check Link usage logs and final charges; retries can incur additional usage.

Source checked

Reference and Check Sources

Next step

Test the current API before fixing, migrating, or creating a test key

Use a temporary, limited key to inspect model declarations, token fields, SSE, and tool calls. Review current models and pricing only when you need a replacement API.

Model Quality CheckModel PricingCreate Account