Chat API Usage Guide
Radient's Chat API is OpenAI-compatible: point an existing OpenAI client at https://api.radienthq.com/v1, use your Radient API key, and calls are billed to your Radient Pass.
The examples below were executed against the API; where a body is trimmed, a … marks the cut and the surrounding figures are as returned.
#Send a chat completion request
curl https://api.radienthq.com/v1/chat/completions \
-H "Authorization: Bearer $RADIENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "auto",
"max_tokens": 16,
"messages": [
{ "role": "user", "content": "Reply with the single word: pong" }
]
}'
{
"id": "gen-…",
"object": "chat.completion",
"created": 1791564194,
"model": "…",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "pong" },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 1402,
"completion_tokens": 45,
"total_tokens": 1447,
"prompt_tokens_details": { "cached_tokens": 0 },
"completion_tokens_details": { "reasoning_tokens": 18 },
"cost": 0.0001627
},
"cost": {
"v": 1,
"amount_usd": 0.0001627,
"basis": "billed",
"units": 1447,
"unit": "token",
"provider": "openrouter",
"model": "openai/gpt-6-luna-pro",
"usage_record_id": "6ac9dfbf705ad8633a87dfc4"
},
"provider": "…"
}
model and provider are trimmed above: they identify the model that served the request and its serving endpoint (see Radient Automatic).
#Request
POST /v1/chat/completions accepts the standard OpenAI chat parameters:
| Field | Type | Notes |
|---|---|---|
model | string | "auto" (recommended) or a model id from GET /v1/models |
messages | array | {role, content} objects; role is system, user, assistant or tool; content is a string or a list of content parts (text, image_url, …) |
max_tokens / max_completion_tokens | integer | Output cap |
temperature, top_p, frequency_penalty, presence_penalty | number | Sampling controls |
stop, n, seed, logprobs, top_logprobs, logit_bias | — | As per the OpenAI API |
response_format | object | e.g. {"type": "json_object"} |
stream | boolean | SSE streaming — see below |
stream_options | object | {"include_usage": true} adds a final usage frame |
tools, tool_choice, parallel_tool_calls | — | Function calling — see below |
reasoning_effort / reasoning | string / object | "auto" is a Radient-defined special value; other values pass through — see Radient Automatic |
Notes:
- There is no server-side range checking; invalid values are forwarded to the serving model and fail there.
- Unknown fields are ignored.
POST /v1/completions(the legacy text-completion endpoint) is also available. Withmodel: "auto"it always uses the default model — the router has no chat content to classify — so prefer the chat endpoint.
#Response
| Field | Meaning |
|---|---|
id, object, created | Request metadata (object is chat.completion) |
model | The model that served the request |
provider | The serving endpoint |
choices[] | {index, message: {role, content, …}, finish_reason}; finish_reason is stop, length, tool_calls, … |
usage | prompt_tokens, completion_tokens, total_tokens, optional prompt_tokens_details.cached_tokens and completion_tokens_details, and cost in USD |
cost | The versioned cost object for this call — the amount deducted from your balance, with the usage-record id it lands on. See Cost reporting. |
The cost object states what the call was charged; usage.cost mirrors the same figure. Some serving models add their own fields inside message (for example reasoning text); treat unknown fields as informational.
#Streaming
Set "stream": true to receive Server-Sent Events:
curl -N https://api.radienthq.com/v1/chat/completions \
-H "Authorization: Bearer $RADIENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "auto",
"stream": true,
"stream_options": { "include_usage": true },
"max_tokens": 16,
"messages": [{ "role": "user", "content": "Say pong" }]
}'
Each event is a chat.completion.chunk; the stream ends with data: [DONE]:
data: {"id":"gen-…","object":"chat.completion.chunk","created":…,"model":"…","choices":[{"index":0,"delta":{"content":"pong","role":"assistant"},"finish_reason":null}]}
data: {"id":"gen-…","object":"chat.completion.chunk","created":…,"model":"…","choices":[{"index":0,"delta":{"content":""},"finish_reason":"stop"}],"usage":{"prompt_tokens":1407,"completion_tokens":54,"total_tokens":1461,"cost":0.0001677,…},"cost":{"v":1,"amount_usd":0.0001677,"basis":"billed","units":1461,"unit":"token","provider":"openrouter","model":"openai/gpt-6-luna-pro","usage_record_id":"6aca94d457c97c7ea474387c"}}
data: [DONE]
(Trimmed. Chunks carry model, provider and other metadata on each frame; the last frame before [DONE] carries usage — and the cost object — when the stream reports usage.)
Behaviour worth knowing:
- The
usagechunk arrives only ifinclude_usageis requested — or when the route always reports usage, asautodoes today. The billed amount is in thecostobject on the last usage frame (earlier frames state their own running figures). A frame that states no figure and has no platform rate to derive one from is forwarded as-is and carries no object, and a stream that reports no usage frame carries no object anywhere — reconcile either through the usage surface. Billing happens regardless. See Cost reporting. - Streaming is subject to a 5-minute server-side cap per request; long generations should chunk their work.
- The
200 text/event-streamstatus is sent before the serving model is contacted. A failure after that point cannot change the status: the client sees an empty or truncated stream. Validate content and watch for a missing[DONE]. Accept: text/event-streamis not required.
#Tool calls (function calling)
tools with a tool_choice works on chat completions (including auto). When the model decides to call a function, finish_reason is tool_calls and message.tool_calls lists the calls; return the result as a role: "tool" message with tool_call_id, then call again.
{
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_…",
"type": "function",
"function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" }
}
]
},
"finish_reason": "tool_calls"
}
]
}
(Trimmed.) arguments is a JSON string — parse it before use.
#Python example
import requests
RADIENT_API_KEY = "YOUR_RADIENT_API_KEY"
RADIENT_BASE_URL = "https://api.radienthq.com/v1"
headers = {
"Authorization": f"Bearer {RADIENT_API_KEY}",
"Content-Type": "application/json",
}
payload = {
"model": "auto",
"messages": [
{"role": "system", "content": "You are a witty assistant that loves to tell jokes."},
{"role": "user", "content": "Tell me a joke about programming."},
],
"temperature": 0.7,
"max_tokens": 150,
}
response = requests.post(f"{RADIENT_BASE_URL}/chat/completions", headers=headers, json=payload)
response.raise_for_status()
completion_data = response.json()
print("Assistant:", completion_data["choices"][0]["message"]["content"])
print("Cost (USD):", completion_data["cost"]["amount_usd"])
#Errors
| Status | Body | Cause |
|---|---|---|
400 | {"error":"Invalid request format"} | The body is not valid JSON |
401 | {"error":"missing Authorization header"} (no credential) · invalid API key format · invalid API key · API key is not a Radient key | Credential problems — see Authentication |
402 | {"error":"insufficient credits"} | The credit gate refused the call — see the credit gate |
500 | {"error":"Failed to process chat completions request"} | Every serving failure — unknown model, empty messages, upstream errors — is flattened into this one response. The upstream's own message is logged, not returned. |
There is no request-rate limit on this route; it is bounded only by the credit gate and by the serving model's own limits. The API does not emit 429s here. When retrying, inspect the error body rather than assuming a rate limit.
#Billing
Each call's charge is stated in the response's cost object — the amount deducted from your Radient Pass balance, at the serving model's own rate with no markup. On chat, usage.cost mirrors the same figure. A failed call records a zero-cost usage entry, so failures do not consume credits. See Cost reporting.
#Managing conversation history
Include previous turns in messages — the API is stateless:
payload = {
"model": "auto",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "The capital of France is Paris."},
{"role": "user", "content": "What is it famous for?"},
],
}
See also: Radient Automatic · Embeddings API · Usage and credits API · API Reference.