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.