> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lumenfall.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create chat completion

> Generate text responses from a conversation

Modern media applications don't just generate images and videos — they also make dozens of LLM calls for prompting, captioning, moderation, and orchestration. Instead of juggling a separate provider or router for text, you can use the same Lumenfall SDK, API key, and base URL you already use for media generation. One platform, one bill, no context-switching.

<Info>
  **Powered by OpenRouter**

  Text completions are routed through [OpenRouter](https://openrouter.ai/docs/api/api-reference/chat/send-chat-completion-request), giving you access to all hundreds of models available on their platform — from OpenAI, Google, Anthropic, Meta, Mistral, and many more providers. All OpenRouter features are fully supported. Use any model by passing its [OpenRouter model identifier](https://openrouter.ai/models) (e.g., `google/gemini-3-flash-preview`). You can optionally prefix with `openrouter/` (e.g., `openrouter/google/gemini-3-flash-preview`), but it is not required.
</Info>

<Info>
  **OpenAI compatibility**

  This endpoint implements the [OpenAI Chat Completions API](https://platform.openai.com/docs/api-reference/chat). You can use any [OpenAI SDK](/client-libraries/openai-sdk) by changing the base URL to `https://api.lumenfall.ai/openai/v1`.
</Info>

## Request body

<Note>
  You can include additional parameters not listed here. They will be passed through to the underlying provider.
</Note>

<ParamField body="model" type="string" required>
  The model to use. Pass any [OpenRouter model identifier](https://openrouter.ai/models) — for example, `google/gemini-3-flash-preview` or `openai/gpt-5.4`.
</ParamField>

<ParamField body="messages" type="array" required>
  A list of messages comprising the conversation. Each message has a `role` and `content`.

  <Expandable title="Message object">
    <ParamField body="role" type="string" required>
      The role of the message author. One of `system`, `user`, `assistant`, or `tool`.
    </ParamField>

    <ParamField body="content" type="string | array | null" required>
      The content of the message. Can be a string, an array of content parts (for multimodal input), or `null` (for assistant messages with tool calls).

      Content parts support `text` and `image_url` types:

      ```json theme={null}
      [
        { "type": "text", "text": "What's in this image?" },
        { "type": "image_url", "image_url": { "url": "https://example.com/image.png" } }
      ]
      ```
    </ParamField>

    <ParamField body="name" type="string">
      An optional name for the participant.
    </ParamField>

    <ParamField body="tool_calls" type="array">
      Tool calls generated by the model (assistant messages only).
    </ParamField>

    <ParamField body="tool_call_id" type="string">
      The ID of the tool call this message is responding to (tool messages only).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="stream" type="boolean" default="false">
  If `true`, the response is sent as [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE). Partial message deltas are sent as `data: {json}` lines, ending with `data: [DONE]`.
</ParamField>

<ParamField body="temperature" type="number" default="1">
  Sampling temperature between 0 and 2. Higher values make output more random, lower values make it more focused.
</ParamField>

<ParamField body="max_tokens" type="integer">
  The maximum number of tokens to generate.
</ParamField>

<ParamField body="top_p" type="number" default="1">
  Nucleus sampling parameter. Only consider tokens with cumulative probability up to this value.
</ParamField>

<ParamField body="frequency_penalty" type="number" default="0">
  Penalizes tokens based on their frequency in the text so far. Range: -2.0 to 2.0.
</ParamField>

<ParamField body="presence_penalty" type="number" default="0">
  Penalizes tokens based on whether they appear in the text so far. Range: -2.0 to 2.0.
</ParamField>

<ParamField body="stop" type="string | array">
  Up to 4 sequences where the model will stop generating.
</ParamField>

<ParamField body="tools" type="array">
  A list of tools the model may call. Currently only `function` type tools are supported.

  <Expandable title="Tool object">
    <ParamField body="type" type="string" required>
      The type of tool. Currently only `function` is supported.
    </ParamField>

    <ParamField body="function" type="object" required>
      <ParamField body="name" type="string" required>
        The name of the function.
      </ParamField>

      <ParamField body="description" type="string">
        A description of what the function does.
      </ParamField>

      <ParamField body="parameters" type="object">
        The parameters the function accepts, described as a JSON Schema object.
      </ParamField>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="tool_choice" type="string | object">
  Controls which tool the model calls. Options:

  * `"none"` - Do not call any tool
  * `"auto"` - Model decides whether to call a tool
  * `"required"` - Model must call a tool
  * `{"type": "function", "function": {"name": "my_function"}}` - Call a specific function
</ParamField>

<ParamField body="response_format" type="object">
  The format of the response. Set `{"type": "json_object"}` to enable JSON mode.
</ParamField>

<ParamField body="seed" type="integer">
  A seed for deterministic generation. Not all models support this.
</ParamField>

<ParamField body="user" type="string">
  A unique identifier representing your end-user.
</ParamField>

<ParamField body="logprobs" type="boolean" default="false">
  Whether to return log probabilities of the output tokens.
</ParamField>

<ParamField body="top_logprobs" type="integer">
  Number of most likely tokens to return at each position (0-20). Requires `logprobs: true`.
</ParamField>

<ParamField body="stream_options" type="object">
  Options for streaming responses.

  <Expandable title="Stream options">
    <ParamField body="include_usage" type="boolean">
      If `true`, an additional chunk is sent with usage information when streaming.
    </ParamField>
  </Expandable>
</ParamField>

## Response

<ResponseField name="id" type="string">
  A unique identifier for the chat completion.
</ResponseField>

<ResponseField name="object" type="string">
  Always `chat.completion`.
</ResponseField>

<ResponseField name="created" type="integer">
  Unix timestamp of when the completion was created.
</ResponseField>

<ResponseField name="model" type="string">
  The model used for the completion.
</ResponseField>

<ResponseField name="choices" type="array">
  A list of chat completion choices.

  <Expandable title="Choice object">
    <ResponseField name="index" type="integer">
      The index of the choice.
    </ResponseField>

    <ResponseField name="message" type="object">
      The generated message.

      <Expandable title="Message object">
        <ResponseField name="role" type="string">
          Always `assistant`.
        </ResponseField>

        <ResponseField name="content" type="string | null">
          The generated text content, or `null` if the model called a tool.
        </ResponseField>

        <ResponseField name="tool_calls" type="array">
          Tool calls made by the model, if any.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="finish_reason" type="string">
      The reason the model stopped generating. One of `stop`, `length`, `tool_calls`, or `content_filter`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="usage" type="object">
  Token usage statistics for the request.

  <Expandable title="Usage object">
    <ResponseField name="prompt_tokens" type="integer">
      Number of tokens in the prompt.
    </ResponseField>

    <ResponseField name="completion_tokens" type="integer">
      Number of tokens in the generated completion.
    </ResponseField>

    <ResponseField name="total_tokens" type="integer">
      Total number of tokens used.
    </ResponseField>
  </Expandable>
</ResponseField>

## Streaming

When `stream: true` is set, the response is sent as server-sent events. Each event contains a `chat.completion.chunk` object with a `delta` field instead of `message`:

```json theme={null}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1702345678,"model":"google/gemini-3-flash-preview","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}

data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1702345678,"model":"google/gemini-3-flash-preview","choices":[{"index":0,"delta":{"content":"Capybaras"},"finish_reason":null}]}

data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1702345678,"model":"google/gemini-3-flash-preview","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]
```

<RequestExample>
  ```bash HTTP theme={null}
  curl https://api.lumenfall.ai/openai/v1/chat/completions \
    -H "Authorization: Bearer $LUMENFALL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "google/gemini-3-flash-preview",
      "messages": [
        {"role": "user", "content": "Why are capybaras so chill?"}
      ]
    }'
  ```

  ```python Python theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="your-lumenfall-api-key",
      base_url="https://api.lumenfall.ai/openai/v1"
  )

  response = client.chat.completions.create(
      model="google/gemini-3-flash-preview",
      messages=[
          {"role": "user", "content": "Why are capybaras so chill?"}
      ]
  )

  print(response.choices[0].message.content)
  ```

  ```typescript JavaScript / TypeScript theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
    apiKey: "your-lumenfall-api-key",
    baseURL: "https://api.lumenfall.ai/openai/v1",
  });

  const response = await client.chat.completions.create({
    model: "google/gemini-3-flash-preview",
    messages: [
      { role: "user", content: "Why are capybaras so chill?" },
    ],
  });

  console.log(response.choices[0].message.content);
  ```

  ```go Go theme={null}
  package main

  import (
      "context"
      "fmt"

      "github.com/openai/openai-go"
      "github.com/openai/openai-go/option"
  )

  func main() {
      client := openai.NewClient(
          option.WithAPIKey("your-lumenfall-api-key"),
          option.WithBaseURL("https://api.lumenfall.ai/openai/v1"),
      )

      response, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
          Model: openai.F("google/gemini-3-flash-preview"),
          Messages: openai.F([]openai.ChatCompletionMessageParamUnion{
              openai.UserMessage("Why are capybaras so chill?"),
          }),
      })
      if err != nil {
          panic(err)
      }

      fmt.Println(response.Choices[0].Message.Content)
  }
  ```

  ```csharp C# / .NET theme={null}
  using OpenAI;
  using OpenAI.Chat;

  var options = new OpenAIClientOptions
  {
      Endpoint = new Uri("https://api.lumenfall.ai/openai/v1")
  };

  var client = new OpenAIClient("your-lumenfall-api-key", options);
  var chatClient = client.GetChatClient("google/gemini-3-flash-preview");

  ChatCompletion response = await chatClient.CompleteChatAsync(
      [new UserChatMessage("Why are capybaras so chill?")]
  );

  Console.WriteLine(response.Content[0].Text);
  ```

  ```java Java theme={null}
  import com.openai.client.OpenAIClient;
  import com.openai.client.okhttp.OpenAIOkHttpClient;
  import com.openai.models.ChatCompletionCreateParams;
  import com.openai.models.ChatCompletionUserMessageParam;

  OpenAIClient client = OpenAIOkHttpClient.builder()
      .apiKey("your-lumenfall-api-key")
      .baseUrl("https://api.lumenfall.ai/openai/v1")
      .build();

  var params = ChatCompletionCreateParams.builder()
      .model("google/gemini-3-flash-preview")
      .addMessage(ChatCompletionUserMessageParam.builder()
          .content("Why are capybaras so chill?")
          .build())
      .build();

  var response = client.chat().completions().create(params);
  System.out.println(response.choices().get(0).message().content().orElse(null));
  ```

  ```ruby Ruby theme={null}
  require "openai"

  client = OpenAI::Client.new(
    api_key: "your-lumenfall-api-key",
    base_url: "https://api.lumenfall.ai/openai/v1"
  )

  response = client.chat.completions.create(
    model: "google/gemini-3-flash-preview",
    messages: [
      { role: "user", content: "Why are capybaras so chill?" }
    ]
  )

  puts response.choices.first.message.content
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={null}
  {
    "id": "chatcmpl-abc123",
    "object": "chat.completion",
    "created": 1702345678,
    "model": "google/gemini-3-flash-preview",
    "choices": [
      {
        "index": 0,
        "message": {
          "role": "assistant",
          "content": "Capybaras are remarkably calm animals for several reasons. As the largest rodents in the world, they have few natural predators in their South American habitats, which means they haven't evolved a strong flight-or-fight response. They're also highly social and semi-aquatic, spending much of their time lounging in warm water - which would make anyone relaxed!"
        },
        "finish_reason": "stop"
      }
    ],
    "usage": {
      "prompt_tokens": 14,
      "completion_tokens": 71,
      "total_tokens": 85
    }
  }
  ```
</ResponseExample>
