Chat & completions
The native GPUniq chat API — completions, server-side chat sessions with full history, shareable transcripts, the generations library, and natural-language to shell commands.
The native surface at /v1/llm/* returns GPUniq's wrapped envelope and adds
what the OpenAI protocol has no room for: server-side chat sessions, USD cost
on every response, and the generations library.
If you want a drop-in replacement for api.openai.com instead — for Claude
Code, Cursor, Aider or the official SDKs — use
OpenAI compatibility.
Requests are authenticated with X-API-Key: gpuniq_... on native routes
(a dashboard JWT via Authorization: Bearer also works). The default model
when you omit model is claude-haiku-4-5.
Simple chat
response = client.llm.chat("claude-haiku-4-5", "Explain how transformers work")
print(response)
curl -X POST "https://api.gpuniq.com/v1/llm/chat/completions" \
-H "X-API-Key: gpuniq_your_key" \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": "Explain how transformers work"}],
"model": "claude-haiku-4-5"
}'
Chat completion (full)
data = client.llm.chat_completion(
messages=[
{"role": "system", "content": "You are a helpful AI assistant."},
{"role": "user", "content": "What is gradient descent?"},
],
model="claude-sonnet-4-6",
temperature=0.7,
max_tokens=1000,
top_p=0.9,
)
print(data["content"])
print(f"Tokens used: {data['tokens_used']} cost: ${data['cost_usd']:.6f}")
Parameters
List of message objects with role ("system", "user", "assistant") and content.
Model slug (e.g., claude-opus-4-7, gpt-5.2, gemini-3-pro). Defaults to claude-haiku-4-5.
Maximum tokens in the response.
Sampling temperature (0.0-2.0). Higher = more creative.
Top-p nucleus sampling parameter.
A non-streaming request asking for max_tokens > 4096 is rejected up front
with streaming_required. Set "stream": true or use the job-based
long-poll API — see Long generations.
Chat sessions
Persistent conversations stored server-side — the model sees the full history on every call, so you send one message rather than re-uploading the transcript.
Persistent conversations stored server-side — the model sees the full history on every call:
# Create a session
session = client.llm.create_chat_session(
model="claude-sonnet-4-6",
title="Research Assistant",
)
# Send messages within the session
reply = client.llm.send_message(
chat_id=session["id"],
message="What are the key papers on attention mechanisms?",
temperature=0.5,
)
# List all sessions
sessions = client.llm.list_chat_sessions(limit=50)
# Get a session with full message history
full = client.llm.get_chat_session(chat_id=session["id"])
# Update title
client.llm.update_chat_session(chat_id=session["id"], title="New Title")
# Delete
client.llm.delete_chat_session(chat_id=session["id"])
Sharing a transcript
POST /v1/llm/chats/{chat_id}/share returns a public link to a read-only copy
of the conversation, reusing the existing link if one was already created.
Anyone with the token can read it through
GET /v1/llm/chats/shared/{share_token} without a key.
curl -X POST https://api.gpuniq.com/v1/llm/chats/42/share \
-H "X-API-Key: gpuniq_your_key"
Messages and context
| Endpoint | What it does |
|---|---|
GET /v1/llm/chats/{chat_id}/messages | Page through a session's messages. |
DELETE /v1/llm/chats/{chat_id}/messages/{message_id} | Remove one message from the history. |
GET /v1/llm/chats/{chat_id}/context | The messages the next turn will be sent with. Pass ?model= to see the history as trimmed for that model's context window. |
POST /v1/llm/chats/{chat_id}/turns | Record a turn you already generated and paid for on a streaming surface, so it lands in the session history. Never charges. |
Generating images inside a session
Posting to /v1/llm/chats/{chat_id}/messages with an image model puts the
prompt and the resulting image into the chat history as a turn. See
Generating an image inside a chat session.
The generations library
Every image, video, music and audio generation you run is recorded. GET /v1/llm/generations returns a page of them, newest first.
| Query parameter | Effect |
|---|---|
kind | Filter by media kind. |
model | Filter by model slug. |
q | Free-text search over prompts. |
limit | Page size, default 40. |
before_id | Pass the previous page's next_before_id to continue. A null there means there is nothing older. |
GET /v1/llm/generations/{generation_id} returns one in full; DELETE on the
same path removes it.
curl "https://api.gpuniq.com/v1/llm/generations?kind=video&limit=20" \
-H "X-API-Key: gpuniq_your_key"
Generate terminal commands
POST /v1/llm/generate-commands turns a natural-language task into an ordered
list of shell commands, each annotated with a danger_level. The Python SDK has
no helper for this endpoint — call it over HTTP.
| Field | Type | Notes |
|---|---|---|
prompt | string | Required, 1–1000 characters. |
max_commands | int | 1–10, default 5. |
model | string | Optional; the server default is used when omitted. |
context | object | Optional — OS, shell history, environment. |
import requests
body = requests.post(
"https://api.gpuniq.com/v1/llm/generate-commands",
headers={"X-API-Key": "gpuniq_your_key"},
json={"prompt": "find all Python files larger than 1MB and sort by size",
"max_commands": 5},
).json()
if body["exception"] != 0: # refusals arrive as HTTP 200
raise RuntimeError(body["data"])
for c in body["data"]["commands"]:
print(f"[{c['danger_level']}] {c['command']} # {c['description']}")
The response also carries explanation, warnings, alternatives,
tokens_used, cost_usd and balance_usd. Per-command fields beyond
command, description and danger_level (step, requires_confirmation,
expected_output) are written by the model and may be missing. If the model's
reply cannot be parsed, commands comes back empty with the reason in
explanation — treat an empty list as a result to handle, not as success.
This endpoint predates the shared error catalog: its error_code values are
upper-case (INSUFFICIENT_BALANCE), unlike the lower-case codes on every
other surface. Compare case-insensitively if you branch on them.
Errors
Every failure returns a structured error_code you can branch on. The full
catalog, envelope shapes and recovery recipes live in the
Error reference.