Chat and streaming
POST
/v1/chat/completionsThe main endpoint for text models. Its request and response format match OpenAI Chat Completions.
Request
curl https://api-dev.satulink.ai/v1/chat/completions \
-H "Authorization: Bearer $SATULINK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v-4.1-flash",
"messages": [{ "role": "user", "content": "Halo!" }],
"max_tokens": 512
}'import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.SATULINK_API_KEY,
baseURL: "https://api-dev.satulink.ai/v1",
});
const completion = await client.chat.completions.create({
model: "deepseek-v-4.1-flash",
messages: [{ role: "user", content: "Halo!" }],
max_tokens: 512,
});
console.log(completion.choices[0].message.content);import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["SATULINK_API_KEY"],
base_url="https://api-dev.satulink.ai/v1",
)
completion = client.chat.completions.create(
model="deepseek-v-4.1-flash",
messages=[{"role": "user", "content": "Halo!"}],
max_tokens=512,
)
print(completion.choices[0].message.content)<?php
$ch = curl_init("https://api-dev.satulink.ai/v1/chat/completions");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("SATULINK_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"model" => "deepseek-v-4.1-flash",
"messages" => [["role" => "user", "content" => "Halo!"]],
"max_tokens" => 512,
]),
]);
echo curl_exec($ch);Request fields
| Field | Type | Description |
|---|---|---|
model | string | Required. The public model ID. |
messages | array | Required. A list of messages with a role and content. |
stream | boolean | Optional. true for an event-stream response. |
max_tokens | number | Optional but recommended. Without it the provider uses the full context and a large amount of balance is reserved. |
temperature | number | Optional. Passed through to the provider. |
top_p | number | Optional. Passed through to the provider. |
stop | string / array | Optional. Passed through to the provider. |
tools | array | Optional. See Tool calling. |
tool_choice | string / object | Optional. Passed through to the provider. |
response_format | object | Optional. Passed through as-is. |
Non-streaming response
200 OK
json
{
"id": "chatcmpl-7c1a",
"object": "chat.completion",
"created": 1760000000,
"model": "deepseek-v-4.1-flash",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Halo! Ada yang bisa dibantu?" },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 9,
"total_tokens": 21,
"prompt_tokens_details": { "cached_tokens": 0 },
"cost_idr": 38
}
}finish_reason holds stop, length, tool_calls, function_call, or content_filter.
Streaming
POST
/v1/chat/completionsWith "stream": true, the response is text/event-stream. Each line is data: <json> and entries are separated by one blank line. There is no event: name, and the stream always closes with data: [DONE].
Chunk order
text/event-stream
bash
data: {"id":"chatcmpl-7c1a","object":"chat.completion.chunk","created":1760000000,"model":"deepseek-v-4.1-flash","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-7c1a","object":"chat.completion.chunk","created":1760000000,"model":"deepseek-v-4.1-flash","choices":[{"index":0,"delta":{"content":"Ha"},"finish_reason":null}]}
data: {"id":"chatcmpl-7c1a","object":"chat.completion.chunk","created":1760000000,"model":"deepseek-v-4.1-flash","choices":[{"index":0,"delta":{"content":"lo!"},"finish_reason":null}]}
data: {"id":"chatcmpl-7c1a","object":"chat.completion.chunk","created":1760000000,"model":"deepseek-v-4.1-flash","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-7c1a","object":"chat.completion.chunk","created":1760000000,"model":"deepseek-v-4.1-flash","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":9,"total_tokens":21,"cost_idr":38}}
data: [DONE]A mid-stream failure arrives as data: {"error":{…,"code":"stream_error"}} followed by [DONE]. An error before the stream starts is still plain JSON with a normal HTTP status.
Reading a stream with the SDK
Request
curl -N https://api-dev.satulink.ai/v1/chat/completions \
-H "Authorization: Bearer $SATULINK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v-4.1-flash",
"messages": [{ "role": "user", "content": "Halo!" }],
"stream": true
}'// client dibuat seperti di bagian SDK
const stream = await client.chat.completions.create({
model: "deepseek-v-4.1-flash",
messages: [{ role: "user", content: "Halo!" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}# client dibuat seperti di bagian SDK
stream = client.chat.completions.create(
model="deepseek-v-4.1-flash",
messages=[{"role": "user", "content": "Halo!"}],
stream=True,
)
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="")Still haven't found the answer? Try it directly in Playground or view the list of active models.

