Agent Streaming Chat API SSE Real-Time Output iTick Financial AI Docs SDK & Developer Tools iTick Agent streaming chat API documentation. Provides real-time AI output over SSE with thinking traces, heartbeat keep-alive, thread_id session continuity, and multi-language request examples.

Agent Streaming Chat API Documentation

This SSE (Server-Sent Events) based streaming chat API returns AI responses token by token, with support for thinking trace display and heartbeat keep-alive.

Endpoint Information

ItemDescription
MethodPOST
Path/agent/stream/v1
ProtocolSSE (text/event-stream)
AuthenticationHeader token validation

Request Parameters

Headers

ParameterTypeRequiredDescription
tokenstringYesUser authentication token used for authorization and quota management

Body (JSON)

{
  "input": {
    "messages": [
      {
        "type": "human",
        "content": "Hello, please help me analyze..."
      }
    ]
  },
  "config": {
    "configurable": {
      "thread_id": "Session ID (optional, UUID will be auto-generated if omitted)"
    }
  }
}
FieldTypeRequiredDescription
input.messagesarrayYesConversation message list, supports multi-turn history
input.messages[].typestringYesMessage role: human / user / ai / assistant
input.messages[].contentstringYesMessage text content
config.configurable.thread_idstringNoConversation thread ID. UUID is generated automatically when omitted

Response Format

The response is an SSE stream. Each line begins with data: and contains JSON data.

Thinking Event

Thinking content emitted during model reasoning is wrapped by thinking and response markers:

{"type": "think", "content": " thinkingThe user's question is..."}
{"type": "think", "content": " response"}
  • The first think event starts with thinking, indicating the model has entered the reasoning phase
  • When thinking ends, content: " response" is sent to indicate the switch from reasoning to the final answer

Content Event

{
  "type": "content",
  "content": "Hello!",
  "node": "agent",
  "run_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
FieldTypeDescription
typestringFixed value "content"
contentstringAI response token chunk
nodestringLangGraph node name
run_idstringCurrent run ID (UUID)

Heartbeat

About every second, if the model is still processing, an empty heartbeat frame is sent to keep the connection alive:

data:

Stream End Marker

data: [DONE]

Error Events

Model safety interception:

{
  "type": "error",
  "code": 3,
  "message": "Model output was blocked by safety policy. Please try adjusting the input content."
}

Generic exception:

{
  "error": "ExceptionClassName",
  "message": "Error details"
}

Token authentication failure:

{
  "type": "package permission not enough",
  "code": 2002
}
Error CodeDescription
2002Token is invalid, missing, or out of quota
3Content was blocked by safety policy

Authentication Logic

  1. Read token from the request header.
  2. Use TokenAuthManager to verify that the token has a valid authorization record in Redis.
  3. Verify whether the token has expired via expire_time.
  4. Verify whether the token's credits quota has been exhausted based on estimated input/output token usage.

If any validation fails, the API returns an error with code: 2002.

Request Examples

cURL (quick test)

curl -X POST https://agent.itick.org/agent/stream/v1 \
  -H "Content-Type: application/json" \
  -H "token: your_token_here" \
  -d '{
    "input": {
      "messages": [
        {"type": "human", "content": "Hello, please introduce yourself"}
      ]
    },
    "config": {
      "configurable": {
        "thread_id": "session-001"
      }
    }
  }'

Go

package main

import (
    "bufio"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "strings"
)

const (
    apiURL = "https://agent.itick.org/agent/stream/v1"
    token  = "your_token_here"
)

type RequestBody struct {
    Input struct {
        Messages []Message `json:"messages"`
    } `json:"input"`
    Config struct {
        Configurable struct {
            ThreadID string `json:"thread_id"`
        } `json:"configurable"`
    } `json:"config"`
}

type Message struct {
    Type    string `json:"type"`
    Content string `json:"content"`
}

func main() {
    body := RequestBody{}
    body.Input.Messages = []Message{
        {Type: "human", Content: "Hello, please introduce yourself"},
    }
    body.Config.Configurable.ThreadID = "session-001"

    jsonBody, _ := json.Marshal(body)

    req, _ := http.NewRequest("POST", apiURL, strings.NewReader(string(jsonBody)))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("token", token)

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Request failed:", err)
        return
    }
    defer resp.Body.Close()

    reader := bufio.NewReader(resp.Body)
    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            if err == io.EOF {
                break
            }
            fmt.Println("Read failed:", err)
            break
        }
        line = strings.TrimSpace(line)
        if line == "" {
            continue
        }
        if strings.HasPrefix(line, "data: ") {
            dataStr := line[6:]
            if dataStr == "[DONE]" {
                fmt.Println("=== Stream finished ===")
                break
            }
            fmt.Println(dataStr)
        }
    }
}

Python

import json
import requests

url = "https://agent.itick.org/agent/stream/v1"
headers = {
    "Content-Type": "application/json",
    "token": "your_token_here"
}
body = {
    "input": {
        "messages": [
            {"type": "human", "content": "Hello, please introduce yourself"}
        ]
    },
    "config": {
        "configurable": {
            "thread_id": "session-001"
        }
    }
}

response = requests.post(url, headers=headers, json=body, stream=True)

for line in response.iter_lines():
    if not line:
        continue
    line = line.decode("utf-8")
    if line.startswith("data: "):
        data_str = line[6:]
        if data_str == "[DONE]":
            print("=== Stream finished ===")
            break
        data = json.loads(data_str)
        print(data)

Java

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;

public class AgentStreamClient {

    private static final String API_URL = "https://agent.itick.org/agent/stream/v1";
    private static final String TOKEN = "your_token_here";

    public static void main(String[] args) throws Exception {
        String jsonBody = """
            {
                "input": {
                    "messages": [
                        {"type": "human", "content": "Hello, please introduce yourself"}
                    ]
                },
                "config": {
                    "configurable": {
                        "thread_id": "session-001"
                    }
                }
            }
            """;

        URL url = new URI(API_URL).toURL();
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestProperty("token", TOKEN);
        conn.setDoOutput(true);
        conn.setConnectTimeout(10000);
        conn.setReadTimeout(300000);

        try (OutputStream os = conn.getOutputStream()) {
            os.write(jsonBody.getBytes("UTF-8"));
            os.flush();
        }

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(conn.getInputStream(), "UTF-8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.isEmpty()) {
                    continue;
                }
                if (line.startsWith("data: ")) {
                    String dataStr = line.substring(6);
                    if ("[DONE]".equals(dataStr)) {
                        System.out.println("=== Stream finished ===");
                        break;
                    }
                    System.out.println(dataStr);
                }
            }
        }

        conn.disconnect();
    }
}

Node.js

const API_URL = "https://agent.itick.org/agent/stream/v1";
const TOKEN = "your_token_here";

async function streamChat() {
  const response = await fetch(API_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "token": TOKEN,
    },
    body: JSON.stringify({
      input: {
        messages: [{ type: "human", content: "Hello, please introduce yourself" }]
      },
      config: {
        configurable: { thread_id: "session-001" },
      },
    }),
  });

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    const text = decoder.decode(value, { stream: true });
    const lines = text.split("\n");
    for (const line of lines) {
      if (line.startsWith("data: ")) {
        const dataStr = line.slice(6);
        if (dataStr === "[DONE]") {
          console.log("=== Stream finished ===");
          return;
        }
        if (dataStr) {
          console.log(JSON.parse(dataStr));
        }
      }
    }
  }
}

streamChat().catch(console.error);

Notes

  1. Connection keep-alive: The API sends heartbeat frames every second to prevent proxies such as Nginx from timing out the connection. Configure Nginx with proxy_buffering off or X-Accel-Buffering: no.
  2. Client disconnect detection: The server detects disconnects in real time and immediately cancels the LangGraph task to save LLM compute.
  3. Multi-turn conversations: The messages array supports complete conversation history. The server automatically converts dict style messages into LangChain message objects.
  4. thread_id: Clients should maintain thread_id to preserve conversation context across turns. If omitted, a new session is created for each request.
  1. Agent SDK

    Official iTick Agent SDK providing plug-and-play AI chat capabilities for financial information platforms. Features ShadowDOM style isolation, virtual scrolling, Markdown rendering, streaming SSE output, and React/Vue 3 framework wrappers.

  2. Subscribe and Renew

    How to subscribe and renew package plans on the iTick platform. The complete process of selecting a package, confirming orders, and completing payments, along with renewal operation guidelines to help users easily manage service subscriptions.