Chat Models API
Img2Vid exposes active chat models through several public API formats so code agents and backend integrations can use the same configured chat models without depending on Img2Vid's browser UI.
The chat API is separate from the media generation API. Use /api/v1/models for chat models. Use /api/v1/media_models for image, video, audio, and music generation models.
Authentication
All chat API endpoints require a server-side API key.
Authorization: Bearer $BUBLE_API_KEY
X-API-Key: $BUBLE_API_KEY is also accepted.
Endpoints
| Method | Endpoint | Format | Purpose |
|---|---|---|---|
GET |
/api/v1/models |
OpenAI-style model list | List active chat models. |
POST |
/api/v1/chat/completions |
OpenAI chat completions style | Create a chat completion or stream chunks. |
POST |
/api/v1/messages |
Anthropic Messages style | Create a message response or stream events. |
POST |
/api/v1beta/models/{model}:generateContent |
Gemini generateContent style | Generate non-streaming model content. |
POST |
/api/v1beta/models/{model}:streamGenerateContent |
Gemini streamGenerateContent style | Stream generated model content. |
OpenAI-compatible and Anthropic-compatible endpoints use stream: true for streaming. Gemini-compatible streaming uses the standard :streamGenerateContent method instead of stream: true.
List chat models
GET /api/v1/models
Example request
curl https://img2vid.net/api/v1/models \
-H "Authorization: Bearer $BUBLE_API_KEY"
Response shape
{
"object": "list",
"data": [
{
"id": "openai/gpt-5.5",
"object": "model",
"created": 1778716800,
"owned_by": "OpenAI",
"name": "GPT-5.5",
"description": "High-capability chat model.",
"capabilities": {
"reasoning": true,
"attachments": true,
"tools": true
},
"tags": ["chat"]
}
]
}
Model fields
| Field | Description |
|---|---|
id |
Stable model key to pass as model. |
object |
Always model. |
created |
Model creation time as Unix seconds. |
owned_by |
Vendor or provider display name. |
name |
Human-readable model name. |
description |
Optional model description. |
capabilities |
Public feature flags derived from the active chat model configuration. |
tags |
Optional tags configured for the model. |
OpenAI-compatible chat completions
POST /api/v1/chat/completions
Content-Type: application/json
Request body
| Field | Type | Required | Description |
|---|---|---|---|
model |
string | Yes | Chat model key from /api/v1/models. |
messages |
array | Yes | OpenAI-style chat messages. At least one non-system message is required. |
stream |
boolean | No | When true, returns OpenAI-compatible server-sent events. |
temperature |
number | No | Forwarded only when the selected model exposes this configured option. |
top_p |
number | No | Forwarded only when the selected model exposes this configured option. |
stop |
string or array | No | Forwarded only when the selected model exposes this configured option. |
presence_penalty |
number | No | Forwarded only when the selected model exposes this configured option. |
frequency_penalty |
number | No | Forwarded only when the selected model exposes this configured option. |
response_format |
object | No | Forwarded only when the selected model exposes this configured option. |
seed |
number | No | Forwarded only when the selected model exposes this configured option. |
options |
object | No | Model-specific options configured for the selected chat model. |
extra_body |
object | No | Merged into model options before validation. |
tools |
array | No | OpenAI-compatible tool definitions. Requires model capabilities.tools. |
tool_choice |
string or object | No | OpenAI-compatible tool choice. Requires model capabilities.tools. |
parallel_tool_calls |
boolean | No | OpenAI-compatible parallel tool call control. Requires model capabilities.tools. |
reasoning |
boolean | No | Enables reasoning only when the model configuration supports reasoning. |
reasoning_effort |
string or boolean | No | Treated as a reasoning enable flag; send provider-specific effort values through options. |
max_tokens |
number | No | Requested output cap. It may be reduced by Img2Vid's billing reservation cap. |
max_completion_tokens |
number | No | Alternative OpenAI-style output cap. |
Supported message content
messages[].content can be a string or an array of content parts.
| Part type | Accepted fields | Result inside Img2Vid |
|---|---|---|
text |
text |
Text part. |
input_text |
text |
Text part. |
image_url |
image_url as string or { "url": "..." } |
File attachment with image media type. |
file |
file.file_data, file.url, or url |
File attachment with optional media type and name. |
Attachments are accepted only if the selected chat model configuration allows that file type.
Example request
curl https://img2vid.net/api/v1/chat/completions \
-H "Authorization: Bearer $BUBLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5.5",
"messages": [
{
"role": "system",
"content": "You are a concise product analyst."
},
{
"role": "user",
"content": "Summarize the main tradeoffs in this launch plan."
}
],
"temperature": 0.4,
"reasoning": true,
"max_completion_tokens": 800
}'
Response shape
{
"id": "chatcmpl-8c3d1f6b-5f04-4a8f-b75a-80f1c49e0a8d",
"object": "chat.completion",
"created": 1778716800,
"model": "openai/gpt-5.5",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Here are the main tradeoffs..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 120,
"completion_tokens": 260,
"total_tokens": 380
}
}
If the provider returns reasoning text and the model supports it, message.reasoning_content can be included. If the provider reports reasoning or cached input tokens, usage.completion_tokens_details.reasoning_tokens and usage.prompt_tokens_details.cached_tokens can be included.
Streaming response
Set stream: true to receive OpenAI-compatible server-sent events:
curl https://img2vid.net/api/v1/chat/completions \
-H "Authorization: Bearer $BUBLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5.5",
"stream": true,
"messages": [
{
"role": "user",
"content": "Write a short launch summary."
}
]
}'
Streaming chunks use chat.completion.chunk objects and end with data: [DONE].
Anthropic-compatible Messages
POST /api/v1/messages
Content-Type: application/json
Request body
| Field | Type | Required | Description |
|---|---|---|---|
model |
string | Yes | Chat model key from /api/v1/models. |
system |
string | No | Converted into a system message. |
messages |
array | Yes | Anthropic-style messages. At least one non-system message is required after conversion. |
stream |
boolean | No | When true, returns Anthropic-compatible server-sent events. |
max_tokens |
number | No | Requested output cap. It may be reduced by Img2Vid's billing reservation cap. |
temperature |
number | No | Forwarded only when the selected model exposes this configured option. |
top_p |
number | No | Forwarded only when the selected model exposes this configured option. |
top_k |
number | No | Forwarded only when the selected model exposes this configured option. |
stop_sequences |
array | No | Mapped to the internal stop option when supported by the selected model. |
options |
object | No | Model-specific options configured for the selected chat model. |
tools |
array | No | Anthropic-compatible tool definitions. Requires model capabilities.tools. |
tool_choice |
object | No | Anthropic-compatible tool choice. Requires model capabilities.tools. |
thinking |
boolean/object | No | Enables reasoning only when the model configuration supports reasoning. |
reasoning |
boolean | No | Alternative reasoning enable flag. |
Supported message content
messages[].content can be a string or an array of content blocks.
| Block type | Accepted fields | Result inside Img2Vid |
|---|---|---|
text |
text |
Text part. |
image |
source.type: "url" with source.url |
Image file attachment. |
image |
source.type: "base64" with source.data |
Data URL image file attachment. |
document |
source.type: "url" with source.url |
Document file attachment. |
Example request
curl https://img2vid.net/api/v1/messages \
-H "Authorization: Bearer $BUBLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5.5",
"system": "You are a concise product analyst.",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Summarize the main tradeoffs in this launch plan."
}
]
}
],
"max_tokens": 800,
"temperature": 0.4
}'
Response shape
{
"id": "msg_8c3d1f6b5f044a8fb75a80f1c49e0a8d",
"type": "message",
"role": "assistant",
"model": "openai/gpt-5.5",
"content": [
{
"type": "text",
"text": "Here are the main tradeoffs..."
}
],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 120,
"output_tokens": 260
}
}
If reasoning text is returned, the response also includes:
{
"thinking": [
{
"type": "thinking",
"thinking": "Reasoning text returned by the provider."
}
]
}
Streaming response
Set stream: true to receive Anthropic-compatible server-sent events:
curl https://img2vid.net/api/v1/messages \
-H "Authorization: Bearer $BUBLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5.5",
"stream": true,
"messages": [
{
"role": "user",
"content": "Write a short launch summary."
}
]
}'
The stream uses events such as message_start, content_block_delta, message_delta, and message_stop.
Gemini-compatible generateContent
POST /api/v1beta/models/{model}:generateContent
Content-Type: application/json
The {model} path value is the Img2Vid chat model key. Model keys that contain / can be used as path segments, for example /api/v1beta/models/openai/gpt-5.5:generateContent.
Use :generateContent for non-streaming Gemini-compatible requests. Use :streamGenerateContent for streaming. Do not use stream: true with :generateContent.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
contents |
array | Yes | Gemini-style content list. At least one non-system message is required after conversion. |
systemInstruction |
object | No | parts are converted into a system message. |
generationConfig |
object | No | Accepts temperature, topP, topK, stopSequences, and maxOutputTokens. |
generation_config |
object | No | Snake-case alternative for generationConfig. |
options |
object | No | Model-specific options configured for the selected chat model. |
tools |
array | No | Gemini-compatible tool declarations. Requires model capabilities.tools. |
toolConfig |
object | No | Gemini-compatible tool configuration. Requires model capabilities.tools. |
reasoning |
boolean | No | Enables reasoning only when the model configuration supports reasoning. |
thinkingConfig |
object | No | Treated as a reasoning enable flag; provider-specific fields must be configured as options. |
Supported parts
| Part field | Result inside Img2Vid |
|---|---|
text |
Text part. |
fileData.fileUri |
File attachment URL. |
file_data.file_uri |
File attachment URL. |
inlineData.data |
Base64 data URL attachment. |
inline_data.data |
Base64 data URL attachment. |
contents[].role value model is converted to an assistant message. Other roles are converted to user messages.
Example request
curl https://img2vid.net/api/v1beta/models/openai/gpt-5.5:generateContent \
-H "Authorization: Bearer $BUBLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"systemInstruction": {
"parts": [
{
"text": "You are a concise product analyst."
}
]
},
"contents": [
{
"role": "user",
"parts": [
{
"text": "Summarize the main tradeoffs in this launch plan."
}
]
}
],
"generationConfig": {
"temperature": 0.4,
"maxOutputTokens": 800
}
}'
Response shape
{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"text": "Here are the main tradeoffs..."
}
]
},
"finishReason": "STOP",
"index": 0
}
],
"usageMetadata": {
"promptTokenCount": 120,
"candidatesTokenCount": 260,
"totalTokenCount": 380
},
"modelVersion": "openai/gpt-5.5"
}
Gemini-compatible streamGenerateContent
POST /api/v1beta/models/{model}:streamGenerateContent
Content-Type: application/json
The request body is the same shape as :generateContent, but the response is returned as server-sent events.
Example request
curl https://img2vid.net/api/v1beta/models/openai/gpt-5.5:streamGenerateContent \
-H "Authorization: Bearer $BUBLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Write a short launch summary."
}
]
}
],
"generationConfig": {
"maxOutputTokens": 800
}
}'
Each streaming chunk is a Gemini-compatible GenerateContentResponse JSON object.
SDK examples
The SDKs expose the same three chat protocol families as the HTTP API. OpenAI-compatible and Anthropic-compatible streaming set stream: true for you. Gemini-compatible streaming uses the dedicated streamGenerateContent / stream_generate_content method and calls /api/v1beta/models/{model}:streamGenerateContent.
The snippets below assume you have already initialized the SDK client as shown in the Quickstart and imported the required language SDK types.
JavaScript / TypeScript
const completion = await buble.chat.completions.create({
model: 'openai/gpt-5.5',
messages: [{ role: 'user', content: 'Write a short launch summary.' }],
max_completion_tokens: 800,
});
const stream = await buble.chat.completions.stream({
model: 'openai/gpt-5.5',
messages: [{ role: 'user', content: 'Write one sentence at a time.' }],
});
for await (const text of stream.toTextStream()) {
process.stdout.write(text);
}
Python
completion = client.chat.completions.create(
model="openai/gpt-5.5",
messages=[{"role": "user", "content": "Write a short launch summary."}],
max_completion_tokens=800,
)
for text in client.chat.completions.stream_text(
model="openai/gpt-5.5",
messages=[{"role": "user", "content": "Write one sentence at a time."}],
):
print(text, end="")
Go
completion, err := client.Chat.Completions.Create(ctx, buble.ChatRequest{
"model": "openai/gpt-5.5",
"messages": []any{
map[string]any{"role": "user", "content": "Write a short launch summary."},
},
"max_completion_tokens": 800,
})
if err != nil {
return err
}
stream, err := client.Chat.Completions.Stream(ctx, buble.ChatRequest{
"model": "openai/gpt-5.5",
"messages": []any{
map[string]any{"role": "user", "content": "Write one sentence at a time."},
},
})
if err != nil {
return err
}
defer stream.Close()
for stream.Next() {
fmt.Print(stream.Text())
}
Rust
use futures_util::StreamExt;
let completion = client.chat().completions().create(serde_json::json!({
"model": "openai/gpt-5.5",
"messages": [
{ "role": "user", "content": "Write a short launch summary." }
],
"max_completion_tokens": 800
})).await?;
let mut stream = client.chat().completions().stream_text(serde_json::json!({
"model": "openai/gpt-5.5",
"messages": [
{ "role": "user", "content": "Write one sentence at a time." }
]
})).await?;
while let Some(chunk) = stream.next().await {
print!("{}", chunk?);
}
Swift
let completion = try await client.chat.completions.create([
"model": "openai/gpt-5.5",
"messages": [
["role": "user", "content": "Write a short launch summary."]
],
"max_completion_tokens": 800
])
let stream = try await client.chat.completions.streamText([
"model": "openai/gpt-5.5",
"messages": [
["role": "user", "content": "Write one sentence at a time."]
]
])
for try await text in stream {
print(text, terminator: "")
}
Dart / Flutter
final completion = await client.chat.completions.create({
'model': 'openai/gpt-5.5',
'messages': [
{'role': 'user', 'content': 'Write a short launch summary.'},
],
'max_completion_tokens': 800,
});
final stream = await client.chat.completions.streamText({
'model': 'openai/gpt-5.5',
'messages': [
{'role': 'user', 'content': 'Write one sentence at a time.'},
],
});
await for (final text in stream) {
print(text);
}
Elixir
{:ok, completion} =
Buble.Chat.Completions.create(client, %{
model: "openai/gpt-5.5",
messages: [%{role: "user", content: "Write a short launch summary."}],
max_completion_tokens: 800
})
{:ok, stream} =
Buble.Chat.Completions.stream_text(client, %{
model: "openai/gpt-5.5",
messages: [%{role: "user", content: "Write one sentence at a time."}]
})
Enum.each(stream, &IO.write/1)
Java
var completion = client.chat().completions().create(Map.of(
"model", "openai/gpt-5.5",
"messages", List.of(Map.of("role", "user", "content", "Write a short launch summary.")),
"max_completion_tokens", 800));
try (BubleStream stream = client.chat().completions().stream(Map.of(
"model", "openai/gpt-5.5",
"messages", List.of(Map.of("role", "user", "content", "Write one sentence at a time."))))) {
while (stream.next()) {
System.out.print(stream.text());
}
}
.NET
var completion = await client.Chat.Completions.CreateAsync(new Dictionary<string, object?>
{
["model"] = "openai/gpt-5.5",
["messages"] = new[]
{
new Dictionary<string, object?>
{
["role"] = "user",
["content"] = "Write a short launch summary."
}
},
["max_completion_tokens"] = 800
});
await foreach (var text in client.Chat.Completions.StreamTextAsync(new Dictionary<string, object?>
{
["model"] = "openai/gpt-5.5",
["messages"] = new[]
{
new Dictionary<string, object?>
{
["role"] = "user",
["content"] = "Write one sentence at a time."
}
}
}))
{
Console.Write(text);
}
PHP
$completion = $client->chat()->completions()->create([
'model' => 'openai/gpt-5.5',
'messages' => [
['role' => 'user', 'content' => 'Write a short launch summary.'],
],
'max_completion_tokens' => 800,
]);
foreach ($client->chat()->completions()->streamText([
'model' => 'openai/gpt-5.5',
'messages' => [
['role' => 'user', 'content' => 'Write one sentence at a time.'],
],
]) as $text) {
echo $text;
}
Ruby
completion = client.chat.completions.create(
model: "openai/gpt-5.5",
messages: [
{ role: "user", content: "Write a short launch summary." }
],
max_completion_tokens: 800
)
client.chat.completions.stream_text(
model: "openai/gpt-5.5",
messages: [
{ role: "user", content: "Write one sentence at a time." }
]
).each do |text|
print text
end
Gemini method names
| Language | Non-streaming | Streaming |
|---|---|---|
| JavaScript / TypeScript | buble.chat.gemini.generateContent(model, body) |
buble.chat.gemini.streamGenerateContent(model, body) |
| Python | client.chat.gemini.generate_content(model, **body) |
client.chat.gemini.stream_generate_content(model, **body) |
| Go | client.Chat.Gemini.GenerateContent(ctx, model, body) |
client.Chat.Gemini.StreamGenerateContent(ctx, model, body) |
| Rust | client.chat().gemini().generate_content(model, body) |
client.chat().gemini().stream_generate_content(model, body) |
| Swift | client.chat.gemini.generateContent(model, body) |
client.chat.gemini.streamGenerateContent(model, body) |
| Dart / Flutter | client.chat.gemini.generateContent(model, body) |
client.chat.gemini.streamGenerateContent(model, body) |
| Elixir | Buble.Chat.Gemini.generate_content(client, model, body) |
Buble.Chat.Gemini.stream_generate_content(client, model, body) |
| Java | client.chat().gemini().generateContent(model, body) |
client.chat().gemini().streamGenerateContent(model, body) |
| .NET | client.Chat.Gemini.GenerateContentAsync(model, body) |
client.Chat.Gemini.StreamGenerateContentAsync(model, body) |
| PHP | $client->chat()->gemini()->generateContent($model, $body) |
$client->chat()->gemini()->streamGenerateContent($model, $body) |
| Ruby | client.chat.gemini.generate_content(model, body) |
client.chat.gemini.stream_generate_content(model, body) |
Options and feature flags
Chat model options are validated against the selected model's configured UI options. Standard fields such as temperature, top_p, top_k, and stop are forwarded only when the selected model exposes those options. Model-specific option names should be sent in options.
reasoning is a request-level feature switch. It only takes effect when the selected model's capabilities report support for the feature.
Tool calling follows each public protocol's standard fields. If a request includes standard tool fields but the selected model does not expose capabilities.tools, the API returns tools_not_supported.
Error format
Chat API errors use the same public error envelope as the media API.
{
"error": {
"code": "missing_model",
"message": "model is required."
}
}
Common chat API errors:
| Code | HTTP | Meaning |
|---|---|---|
missing_api_key |
401 | No API key was provided. |
invalid_api_key |
401 | API key is invalid, inactive, or deleted. |
invalid_request_body |
400 | Request body is not a JSON object. |
missing_model |
400 | Required model key is missing. |
invalid_messages |
400 | No valid messages were provided. |
invalid_message_role |
400 | A message role is not system, user, assistant, or tool. |
unsupported_method |
404 | Gemini-compatible route was not :generateContent or :streamGenerateContent. |
model_not_found |
404 | The model is inactive, missing, or not available for chat. |
tools_not_supported |
400 | Tool fields were provided for a model that does not support tool calling. |
internal_error |
500 | Unexpected server-side failure. |