Text Generation
A full list of models can be viewed on the Models page or retrieved dynamically via API endpoints: https://openai.bothub.chat/v1/models and https://bothub.chat/api/v2/replicate/v1/models
For text processing, visual analysis, and much more, BotHub uses the OpenAI gateway. You can make requests via two different endpoints depending on your project architecture: the classic Chat Completions API or the modern Responses API.
Chat Completions API vs Responses API
- Chat Completions API — a classic endpoint built around the familiar role-based system (
system,user,assistant). It is fully compatible with official OpenAI SDKs. A great choice for quick integration and standard chat interfaces. - Responses API — a new multimodal endpoint. It does not require official SDKs, supports both simple string input and complex data arrays, and allows for flexible control over response structure (JSON schemas) and tools.
1. Chat Completions API (Classic Gateway)
This endpoint is fully compatible with OpenAI syntax. You can use official libraries by simply overriding baseURL to https://openai.bothub.chat/v1.
Synchronous Generation
- JS
- Python
- Go
- cURL
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: 'YOUR_BOTHUB_API_KEY',
baseURL: 'https://openai.bothub.chat/v1'
});
async function main() {
const completion = await openai.chat.completions.create({
model: 'claude-opus-5',
messages: [{ role: 'user', content: 'Hello! Tell me about yourself in three words.' }],
});
console.log(completion.choices[0].message.content);
}
main();
from openai import OpenAI
client = OpenAI(
api_key='YOUR_BOTHUB_API_KEY',
base_url='https://openai.bothub.chat/v1'
)
completion = client.chat.completions.create(
model='claude-opus-5',
messages=[{'role': 'user', 'content': 'Hello! Tell me about yourself in three words.'}]
)
print(completion.choices[0].message.content)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go"
"github.com/openai/openai-go/option"
)
func main() {
client := openai.NewClient(
option.WithAPIKey("YOUR_BOTHUB_API_KEY"),
option.WithBaseURL("https://openai.bothub.chat/v1"),
)
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: openai.ChatModel("claude-opus-5"),
Messages: []openai.ChatCompletionMessageParamUnion{
openai.UserMessage("Hello! Tell me about yourself in three words."),
},
})
if err != nil {
panic(err)
}
fmt.Println(completion.Choices[0].Message.Content)
}
curl https://openai.bothub.chat/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_BOTHUB_API_KEY" \
-d '{
"model": "claude-opus-5",
"messages": [{"role": "user", "content": "Hello! Tell me about yourself in three words."}]
}'
Streaming Generation
- JS
- Python
- Go
- cURL
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: 'YOUR_BOTHUB_API_KEY',
baseURL: 'https://openai.bothub.chat/v1'
});
async function main() {
const stream = await openai.chat.completions.create({
model: 'claude-opus-5',
messages: [{ role: 'user', content: 'Write a short story about AI.' }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
}
main();
from openai import OpenAI
client = OpenAI(
api_key='YOUR_BOTHUB_API_KEY',
base_url='https://openai.bothub.chat/v1'
)
stream = client.chat.completions.create(
model='claude-opus-5',
messages=[{'role': 'user', 'content': 'Write a short story about AI.'}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")
package main
import (
"context"
"fmt"
"github.com/openai/openai-go"
"github.com/openai/openai-go/option"
)
func main() {
client := openai.NewClient(
option.WithAPIKey("YOUR_BOTHUB_API_KEY"),
option.WithBaseURL("https://openai.bothub.chat/v1"),
)
stream := client.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{
Model: openai.ChatModel("claude-opus-5"),
Messages: []openai.ChatCompletionMessageParamUnion{
openai.UserMessage("Write a short story about AI."),
},
})
for stream.Next() {
chunk := stream.Current()
if len(chunk.Choices) > 0 {
fmt.Print(chunk.Choices[0].Delta.Content)
}
}
if err := stream.Err(); err != nil {
panic(err)
}
}
curl https://openai.bothub.chat/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_BOTHUB_API_KEY" \
-d '{
"model": "claude-opus-5",
"messages": [{"role": "user", "content": "Write a short story about AI."}],
"stream": true
}'
Example of an OpenAI gateway response:
{
"id": "gen-1779989130-XaEliNRQ9QbSu4dyJgr3",
"object": "chat.completion",
"created": 1779989130,
"model": "anthropic/claude-4.7-opus-fast-20260512",
"provider": "Anthropic",
"system_fingerprint": null,
"service_tier": "default",
"choices": [
{
"index": 0,
"logprobs": null,
"finish_reason": "stop",
"native_finish_reason": "end_turn",
"message": {
"role": "assistant",
"content": "AI assistant from Anthropic.",
"refusal": null,
"reasoning": null
}
}
],
"usage": {
"prompt_tokens": 29,
"completion_tokens": 19,
"total_tokens": 48,
"cost": 0.00372,
"is_byok": false,
"prompt_tokens_details": {
"cached_tokens": 0,
"cache_write_tokens": 0,
"audio_tokens": 0,
"video_tokens": 0
},
"cost_details": {
"upstream_inference_cost": 0.00372,
"upstream_inference_prompt_cost": 0.00087,
"upstream_inference_completions_cost": 0.00285
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"image_tokens": 0,
"audio_tokens": 0
},
"speed": "fast"
}
}
2. Responses API (New Unified Gateway)
This endpoint accepts requests at https://openai.bothub.chat/v1/responses directly via standard HTTP methods. It offers a simplified structure for plain text and advanced control for multi-turn dialogues.
Responses API Alpha does not store conversation history on the server. To maintain context, the client side must pass an array of all previous messages in the input property with each new request.
Option 1: Simple Text Input (String)
- JS
- Python
- Go
- cURL
async function sendRequest() {
const response = await fetch('https://openai.bothub.chat/v1/responses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_BOTHUB_API_KEY'
},
body: JSON.stringify({
model: 'claude-opus-5',
input: 'What is the meaning of life?',
max_output_tokens: 4000
})
});
const result = await response.json();
console.log(result.output[0].content[0].text);
}
sendRequest();
import requests
url = "https://openai.bothub.chat/v1/responses"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_BOTHUB_API_KEY"
}
data = {
"model": "claude-opus-5",
"input": "What is the meaning of life?",
"max_output_tokens": 4000
}
response = requests.post(url, json=data, headers=headers)
result = response.json()
print(result['output'][0]['content'][0]['text'])
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
payload := map[string]any{
"model": "claude-opus-5",
"input": "What is the meaning of life?",
"max_output_tokens": 4000,
}
body, err := json.Marshal(payload)
if err != nil {
panic(err)
}
req, err := http.NewRequest("POST", "https://openai.bothub.chat/v1/responses", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer YOUR_BOTHUB_API_KEY")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
var result map[string]any
if err := json.Unmarshal(data, &result); err != nil {
panic(err)
}
output := result["output"].([]any)
first := output[0].(map[string]any)
content := first["content"].([]any)
text := content[0].(map[string]any)["text"]
fmt.Println(text)
}
curl https://openai.bothub.chat/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_BOTHUB_API_KEY" \
-d '{
"model": "claude-opus-5",
"input": "What is the meaning of life?",
"max_output_tokens": 4000
}'
Option 2: Structured Message Input
Use for complex chats, pass the full chat history. When passing history from assistant, id and status fields are optional.
- JS
- Python
- Go
- cURL
async function sendChat() {
const response = await fetch('https://openai.bothub.chat/v1/responses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_BOTHUB_API_KEY'
},
body: JSON.stringify({
model: 'claude-opus-5',
input: [
{
type: 'message',
role: 'user',
content: [{ type: 'input_text', text: 'What is the capital of France?' }]
},
{
type: 'message',
id: 'msg_internal_123',
status: 'completed',
role: 'assistant',
content: [{ type: 'output_text', text: 'The capital of France is Paris.' }]
},
{
type: 'message',
role: 'user',
content: [{ type: 'input_text', text: 'What is its population?' }]
}
],
max_output_tokens: 4000
})
});
const result = await response.json();
console.log(result.output[0].content[0].text);
}
sendChat();
import requests
url = "https://openai.bothub.chat/v1/responses"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_BOTHUB_API_KEY"
}
data = {
"model": "claude-opus-5",
"input": [
{
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "What is the capital of France?"}]
},
{
"type": "message",
"id": "msg_internal_123",
"status": "completed",
"role": "assistant",
"content": [{"type": "output_text", "text": "The capital of France is Paris."}]
},
{
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "What is its population?"}]
}
],
"max_output_tokens": 4000
}
response = requests.post(url, json=data, headers=headers)
print(response.json()['output'][0]['content'][0]['text'])
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
payload := map[string]any{
"model": "claude-opus-5",
"input": []any{
map[string]any{
"type": "message",
"role": "user",
"content": []any{
map[string]any{"type": "input_text", "text": "What is the capital of France?"},
},
},
map[string]any{
"type": "message",
"id": "msg_internal_123",
"status": "completed",
"role": "assistant",
"content": []any{
map[string]any{"type": "output_text", "text": "The capital of France is Paris."},
},
},
map[string]any{
"type": "message",
"role": "user",
"content": []any{
map[string]any{"type": "input_text", "text": "What is its population?"},
},
},
},
"max_output_tokens": 4000,
}
body, err := json.Marshal(payload)
if err != nil {
panic(err)
}
req, err := http.NewRequest("POST", "https://openai.bothub.chat/v1/responses", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer YOUR_BOTHUB_API_KEY")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
var result map[string]any
if err := json.Unmarshal(data, &result); err != nil {
panic(err)
}
output := result["output"].([]any)
first := output[0].(map[string]any)
content := first["content"].([]any)
text := content[0].(map[string]any)["text"]
fmt.Println(text)
}
curl https://openai.bothub.chat/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_BOTHUB_API_KEY" \
-d '{
"model": "claude-opus-5",
"input": [
{
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "What is the capital of France?"}]
},
{
"type": "message",
"id": "msg_internal_123",
"status": "completed",
"role": "assistant",
"content": [{"type": "output_text", "text": "The capital of France is Paris."}]
},
{
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "What is its population?"}]
}
],
"max_output_tokens": 4000
}'
3. Vision (Image Analysis)
Vision is the ability to send images along with a text prompt so the model can analyze visual content: recognize objects, describe scenes, analyze interfaces, and read text (OCR).
Supported Models
Almost all modern multimodal models available in BotHub are suitable for image analysis:
- OpenAI: the entire
gpt-4o,gpt-4.1lineup and thegpt-5family - Anthropic Claude: current versions of
claude-sonnetandclaude-opus - Google Gemini: fast and advanced
geminimodels
And many other flagship and specialized models.
Image Submission Formats
You can pass an image either as a public URL or as a Base64 encoded string.
Via URL
{
"type": "image_url",
"image_url": {
"url": "https://images.unsplash.com/photo-1579783902614-a3fb3927b6a5"
}
}
Via Base64
{
"type": "image_url",
"image_url": {
"url": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."
}
}
Vision Request Example (Chat Completions API)
- JS
- Python
- Go
- cURL
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: 'YOUR_BOTHUB_API_KEY',
baseURL: 'https://openai.bothub.chat/v1'
});
async function main() {
const res = await openai.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "user",
content: [
{ type: "text", text: "What is depicted in this photo?" },
{
type: "image_url",
image_url: {
url: "https://images.unsplash.com/photo-1579783902614-a3fb3927b6a5"
}
}
]
}
]
});
console.log(res.choices[0].message.content);
}
main();
import base64
from openai import OpenAI
client = OpenAI(
api_key="YOUR_BOTHUB_API_KEY",
base_url="https://openai.bothub.chat/v1"
)
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode("utf-8")
# Example with a local file via Base64
image_path = "image.jpg"
base64_image = encode_image(image_path)
res = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": "What is depicted in this photo?"
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
]
}
]
)
print(res.choices[0].message.content)
package main
import (
"context"
"fmt"
"github.com/openai/openai-go"
"github.com/openai/openai-go/option"
)
func main() {
client := openai.NewClient(
option.WithAPIKey("YOUR_BOTHUB_API_KEY"),
option.WithBaseURL("https://openai.bothub.chat/v1"),
)
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: openai.ChatModel("gpt-4o"),
Messages: []openai.ChatCompletionMessageParamUnion{
openai.UserMessage([]openai.ChatCompletionContentPartUnionParam{
openai.TextContentPart("What is depicted in this photo?"),
openai.ImageContentPart(openai.ChatCompletionContentPartImageImageURLParam{
URL: "https://images.unsplash.com/photo-1579783902614-a3fb3927b6a5",
}),
}),
},
})
if err != nil {
panic(err)
}
fmt.Println(completion.Choices[0].Message.Content)
}
curl https://openai.bothub.chat/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_BOTHUB_API_KEY" \
-d '{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "What is depicted in this photo?"
},
{
"type": "image_url",
"image_url": {
"url": "https://images.unsplash.com/photo-1579783902614-a3fb3927b6a5"
}
}
]
}
]
}'
- For most Vision tasks, it is recommended to use
gpt-4o, as the model provides the best balance between speed, quality, and cost. - If you need to work with long documents, complex diagrams, or large context, pay attention to Claude and Gemini models.
- For local images, use Base64, and for publicly accessible files — use standard URLs.
4. Reasoning Effort
Reasoning models can think more or less before they answer. BotHub accepts the same scale for every model: none, minimal, low, medium, high, xhigh, max.
| Gateway | Parameter |
|---|---|
| Chat Completions API | reasoning_effort |
| Responses API | reasoning.effort |
curl https://openai.bothub.chat/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_BOTHUB_API_KEY" \
-d '{
"model": "glm-5.2",
"reasoning_effort": "medium",
"messages": [{"role": "user", "content": "How many prime numbers are there below 100?"}]
}'
How the level is applied
Each model supports its own part of the scale, and you do not have to keep track of it. If the model does not have the level you sent, the gateway applies the highest level of the model that does not exceed your request. If the model has nothing that low, its lowest level is applied.
| You send | Levels of the model | Applied |
|---|---|---|
low or medium | high, xhigh | high |
max | high, xhigh | xhigh |
xhigh | low, medium, high, max | high |
minimal | none, low, medium, high | low |
none asks the model not to reason. Where reasoning cannot be switched off, the lowest level of the model is applied instead, and the request does not fail.
Which levels a model has
Request GET https://bothub.chat/api/v2/model/list and find the model. Its apiParams array has an entry with the code reasoning_effort. In that entry enum lists the levels of the model, and default is the level preselected in the BotHub chat:
{
"code": "reasoning_effort",
"type": "string",
"enum": ["high", "xhigh"],
"default": "high"
}