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
| Item | Description |
|---|---|
| Method | POST |
| Path | /agent/stream/v1 |
| Protocol | SSE (text/event-stream) |
| Authentication | Header token validation |
Request Parameters
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
token | string | Yes | User 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)"
}
}
}
| Field | Type | Required | Description |
|---|---|---|---|
input.messages | array | Yes | Conversation message list, supports multi-turn history |
input.messages[].type | string | Yes | Message role: human / user / ai / assistant |
input.messages[].content | string | Yes | Message text content |
config.configurable.thread_id | string | No | Conversation 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
thinkevent starts withthinking, 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"
}
| Field | Type | Description |
|---|---|---|
type | string | Fixed value "content" |
content | string | AI response token chunk |
node | string | LangGraph node name |
run_id | string | Current 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 Code | Description |
|---|---|
2002 | Token is invalid, missing, or out of quota |
3 | Content was blocked by safety policy |
Authentication Logic
- Read
tokenfrom the request header. - Use
TokenAuthManagerto verify that the token has a valid authorization record in Redis. - Verify whether the token has expired via
expire_time. - 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
- 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 offorX-Accel-Buffering: no. - Client disconnect detection: The server detects disconnects in real time and immediately cancels the LangGraph task to save LLM compute.
- Multi-turn conversations: The
messagesarray supports complete conversation history. The server automatically convertsdictstyle messages into LangChain message objects. - thread_id: Clients should maintain
thread_idto preserve conversation context across turns. If omitted, a new session is created for each request.
- 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.
- 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.