GlexirDocs
Dashboard

API

Chat Completions

Chat Completions generates a model reply from a list of messages. Glexir supports it for compatibility with existing code. For new work, use the Responses API: it is required for -pro models and for tool calling on gpt-6-astra and gpt-6.1-sol.

The endpoint is OpenAI-compatible: POST https://api.glexir.com/v1/chat/completions.

Create a completion

import Glexir from "@glexir/sdk";

const glexir = new Glexir({ apiKey: process.env.GLEXIR_API_KEY });

const completion = await glexir.chat.completions.create({
  model: "gpt-5.4-mini",
  messages: [
    { role: "developer", content: "You are terse." },
    { role: "user", content: "Name three planets." },
  ],
});

console.log(completion.choices[0]?.message.content);
console.log(completion.usage);

glexir.chat.completions.create(body, options?) returns APIPromise<ChatCompletion>. With stream: true it returns APIPromise<Stream<ChatCompletionChunk>>.

Operations

SDK methodHTTPReturns
chat.completions.create(body, options?)POST /v1/chat/completionsChatCompletion, or Stream<ChatCompletionChunk> with stream: true
chat.completions.stream(body, options?)POST /v1/chat/completions with stream: trueChatCompletionStream
chat.completions.parse(body, options?)POST /v1/chat/completionsPromise<ParsedChatCompletion<T>>
chat.completions.retrieve(id, options?)GET /v1/chat/completions/{id}ChatCompletion
chat.completions.update(id, body, options?)POST /v1/chat/completions/{id}ChatCompletion
chat.completions.list(query?, options?)GET /v1/chat/completionsPagePromise<ChatCompletion>
chat.completions.delete(id, options?)DELETE /v1/chat/completions/{id}ChatCompletionDeleted
chat.completions.messages.list(id, query?, options?)GET /v1/chat/completions/{id}/messagesPagePromise<ChatCompletionStoreMessage>

Every method takes request options as its last argument: { signal, timeout, maxRetries, headers, idempotencyKey }.

Create parameters

ChatCompletionCreateParams is ChatCompletionCreateParamsNonStreaming | ChatCompletionCreateParamsStreaming. Both extend ChatCompletionCreateParamsBase. Unknown fields are sent unchanged.

ChatCompletionCreateParamsBase
modelChatModelrequired
A text model ID, such as gpt-5.4-mini. -pro models return 400: they are only available through /v1/responses.
messagesChatCompletionMessageParam[]required
A non-empty list of messages with role developer, system, user, assistant or tool. See Messages.
streamboolean | nulloptional
Stream the reply as server-sent events. With true, create() returns a Stream.
stream_options{ include_usage?: boolean; include_obfuscation?: boolean } | nulloptional
Streaming only. include_usage: true adds a final chunk with token usage. See Streaming.
toolsChatCompletionTool[]optional
Function and custom tools only. See Tools.
tool_choiceChatCompletionToolChoiceOptionoptional
none, auto, required, { type: "function", function: { name } }, { type: "custom", custom: { name } } or { type: "allowed_tools", allowed_tools: { mode, tools } }.
parallel_tool_callsbooleanoptional
Allow several tool calls in one reply.
response_formatResponseFormatText | ResponseFormatJSONSchema | ResponseFormatJSONObjectoptional
{ type: "text" }, { type: "json_object" }, or { type: "json_schema", json_schema: { name, schema?, description?, strict? } }.
reasoning_effortReasoningEffort | nulloptional
none, minimal, low, medium, high, xhigh or max.
verbosity"low" | "medium" | "high" | nulloptional
How long the reply should be.
max_completion_tokensnumber | nulloptional
Upper bound on generated tokens, including reasoning tokens.
max_tokensnumber | nulloptional
Deprecated. Use max_completion_tokens. Reasoning models reject it.
nnumber | nulloptional
How many choices to generate.
stopstring | string[] | nulloptional
Stop sequences.
temperaturenumber | nulloptional
Sampling temperature.
top_pnumber | nulloptional
Nucleus sampling.
frequency_penaltynumber | nulloptional
Penalise repeated tokens by frequency.
presence_penaltynumber | nulloptional
Penalise tokens that already appeared.
logit_biasRecord<string, number> | nulloptional
Token ID to bias.
logprobsboolean | nulloptional
Return log probabilities of output tokens.
top_logprobsnumber | nulloptional
Most likely tokens to return at each position. Needs logprobs: true.
prediction{ type: "content"; content: string | ChatCompletionContentPartText[] } | nulloptional
Predicted output, to speed up replies that are mostly known in advance.
storeboolean | nulloptional
Store the completion so you can retrieve, update, list and delete it. The gateway forwards your value unchanged. See Stored completions.
metadataRecord<string, string> | nulloptional
Up to 16 key/value pairs. With store: true, at most 15: Glexir uses one key.
service_tierServiceTier | nulloptional
auto, default, flex, scale, priority, fast or ultrafast. Billing and access work as in Responses.
moderationModerationConfig | nulloptional
Inline moderation: { model: "omni-moderation-latest", policy?: { input?: { mode }, output?: { mode } } }.
prompt_cache_keystring | nulloptional
Groups requests that share a prompt prefix. Scoped to your organization by the gateway.
prompt_cache_optionsPromptCacheOptions | nulloptional
mode (implicit or explicit) and ttl (for example 30m).
prompt_cache_retention"in_memory" | "24h" | nulloptional
Deprecated. Use prompt_cache_options.ttl.
safety_identifierstring | nulloptional
A stable ID for your end user. The gateway replaces it with a hashed value derived from your organization and this value.
seednumber | nulloptional
Deprecated.
userstringoptional
Deprecated. Used as the end-user ID when safety_identifier is missing, then removed by the gateway.
web_search_optionsRecord<string, unknown>optional
Rejected with 400 unsupported_on_glexir. Web search is a hosted tool.

The gateway also rejects audio and modalities that include "audio" (audio output is not supported).

Messages

RoleTypecontent
developerChatCompletionDeveloperMessageParamstring | ChatCompletionContentPartText[]
systemChatCompletionSystemMessageParamstring | ChatCompletionContentPartText[]
userChatCompletionUserMessageParamstring | ChatCompletionContentPart[] (text, image, file)
assistantChatCompletionAssistantMessageParamstring, text and refusal parts, or null; plus refusal? and tool_calls?
toolChatCompletionToolMessageParamstring | ChatCompletionContentPartText[], plus tool_call_id

Every role except tool takes an optional name. User content parts:

  • { type: "text", text }
  • { type: "image_url", image_url: { url, detail? } }, where url is an http(s) URL or a data: URL and detail is auto, low, high or original.
  • { type: "file", file: { file_data?, file_id?, filename? } } for PDFs and other files. file_id must be a file you uploaded through Glexir; any other ID returns 404.

Text, image and file parts accept prompt_cache_breakpoint: { mode: "explicit" }.

TypeScript
import Glexir from "@glexir/sdk";

const glexir = new Glexir();

const completion = await glexir.chat.completions.create({
  model: "gpt-5.4-mini",
  messages: [
    {
      role: "user",
      content: [
        { type: "text", text: "What is in this image?" },
        { type: "image_url", image_url: { url: "https://example.com/cat.png", detail: "auto" } },
      ],
    },
  ],
});

console.log(completion.choices[0]?.message.content);

The gateway returns 400 unsupported_on_glexir for messages with an audio field and for input_audio content parts. An empty messages array returns 400.

The ChatCompletion object

ChatCompletion
idstringoptional
The completion ID, for example chatcmpl-....
object"chat.completion"optional
Always chat.completion.
creatednumberoptional
Unix timestamp in seconds.
modelstringoptional
The model that served the request.
choicesChatCompletionChoice[]optional
Each has index, finish_reason (stop, length, tool_calls, content_filter, function_call), logprobs and message.
choices[].messageChatCompletionMessageoptional
role: "assistant", content, refusal, tool_calls? and annotations?.
usageCompletionUsageoptional
prompt_tokens, completion_tokens, total_tokens, plus prompt_tokens_details (cached_tokens, cache_write_tokens, ...) and completion_tokens_details (reasoning_tokens, prediction tokens, ...). Glexir bills from these numbers.
service_tierServiceTier | nulloptional
The tier that actually served the request. Glexir bills at this tier.
metadataRecord<string, string> | nulloptional
Your metadata. Glexir's own key is removed.
moderationobject | nulloptional
Moderation results when you set moderation.
system_fingerprintstringoptional
Deprecated.
_request_idstring | nulloptional
Added by the SDK: the x-request-id header.

Streaming

Set stream: true on create() for a raw Stream<ChatCompletionChunk>, or use chat.completions.stream() for a helper that assembles the final completion. Both are covered in Streaming.

TypeScript
import Glexir from "@glexir/sdk";

const glexir = new Glexir();

const stream = await glexir.chat.completions.create({
  model: "gpt-5.4-mini",
  messages: [{ role: "user", content: "Count to five." }],
  stream: true,
  stream_options: { include_usage: true },
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta.content ?? "");
  if (chunk.usage) console.log("\n", chunk.usage);
}
Shell
curl -N https://api.glexir.com/v1/chat/completions \
  -H "Authorization: Bearer $GLEXIR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.4-mini",
    "messages": [{ "role": "user", "content": "Count to five." }],
    "stream": true,
    "stream_options": { "include_usage": true }
  }'

include_usage

With stream_options: { include_usage: true }, the last chunk before [DONE] has an empty choices array and a usage object. Guard chunk.choices[0] as above.

Glexir always turns include_usage on when it talks to OpenAI, because it bills streams from that chunk. If you didn't ask for it, the gateway removes the usage chunk before it reaches you. If a stream ends without usage (for example, the upstream fails), Glexir bills an estimate of the input tokens only.

ChatCompletionChunk has id, object: "chat.completion.chunk", created, model, choices (each with index, delta, finish_reason and logprobs?), and usage?, service_tier?, obfuscation? and error?. A delta has role?, content?, refusal? and tool_calls? fragments.

Tools

Chat Completions accepts function and custom tools:

  • ChatCompletionFunctionTool: { type: "function", function: { name, description?, parameters?, strict? } }. Chat Completions is non-strict unless you set strict: true.
  • ChatCompletionCustomTool: { type: "custom", custom: { name, description?, format? } }. format is { type: "text" } or { type: "grammar", grammar: { definition, syntax: "lark" | "regex" } }. The grammar is nested under grammar, unlike the Responses API.

Any other tool type, and any tool_choice type other than function, custom or allowed_tools, returns 400 unsupported_on_glexir. That includes OpenAI-hosted tools such as web search.

Tool calling on newer models

On GPT-5.4 and later, Chat Completions supports tools only with reasoning_effort: "none". gpt-6-astra and gpt-6.1-sol need the Responses API for tool calling.

TypeScript
import Glexir, { type ChatCompletionMessageParam, type ChatCompletionTool } from "@glexir/sdk";

const glexir = new Glexir();

const tools: ChatCompletionTool[] = [
  {
    type: "function",
    function: {
      name: "get_weather",
      description: "Current temperature for a city.",
      parameters: {
        type: "object",
        properties: { city: { type: "string" } },
        required: ["city"],
        additionalProperties: false,
      },
      strict: true,
    },
  },
];

const messages: ChatCompletionMessageParam[] = [{ role: "user", content: "What's the weather in Lagos?" }];
const first = await glexir.chat.completions.create({ model: "gpt-5.4-mini", reasoning_effort: "none", messages, tools });
const reply = first.choices[0]?.message;

if (reply?.tool_calls) {
  messages.push({ role: "assistant", content: reply.content, tool_calls: reply.tool_calls });
  for (const call of reply.tool_calls) {
    if (call.type !== "function") continue;
    const { city } = JSON.parse(call.function.arguments) as { city: string };
    messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify({ city, celsius: 31 }) });
  }
  const second = await glexir.chat.completions.create({ model: "gpt-5.4-mini", reasoning_effort: "none", messages, tools });
  console.log(second.choices[0]?.message.content);
}

Structured output

chat.completions.parse(body, options?) creates a completion and parses each choice's message.content when response_format.type is json_schema or json_object. It also parses the arguments of function tools that have strict: true.

TypeScript
import Glexir, { toStrictJsonSchema } from "@glexir/sdk";

const glexir = new Glexir();

interface City {
  name: string;
  country: string;
}

const schema = toStrictJsonSchema({
  type: "object",
  properties: { name: { type: "string" }, country: { type: "string" } },
  required: ["name", "country"],
});

const completion = await glexir.chat.completions.parse<City>({
  model: "gpt-5.4-mini",
  messages: [{ role: "user", content: "Which city is the Eiffel Tower in?" }],
  response_format: { type: "json_schema", json_schema: { name: "city", schema, strict: true } },
});

console.log(completion.choices[0]?.message.parsed?.country);

It returns ParsedChatCompletion<T>:

  • Each choices[].message is a ParsedChatCompletionMessage<T> with parsed: T | null. parsed is null when the model refused or the format is not JSON.
  • Function tool calls are ParsedFunctionToolCall: { id, type: "function", function: { name, arguments, parsed_arguments } }. parsed_arguments is the parsed JSON for strict tools and null otherwise.
  • It throws LengthFinishReasonError if any choice has finish_reason: "length", and ContentFilterFinishReasonError for "content_filter".
  • options is ParseOptions<T>: request options plus validate?: (value: unknown) => T.

Stored completions

Create a completion with store: true to keep it. You can then retrieve, update, list and delete it, and list its messages. These endpoints only see completions created through your Glexir organization; any other ID returns 404 (No chat completion found with id '...').

Glexir tags each stored completion with one metadata key, glexir_customer, to keep your list separate from other organizations. It removes that key from every response, and it counts toward the 16-key limit: a stored completion can have at most 15 of your own keys, or the request returns 400.

TypeScript
import Glexir from "@glexir/sdk";

const glexir = new Glexir();

const created = await glexir.chat.completions.create({
  model: "gpt-5.4-mini",
  messages: [{ role: "user", content: "Hello" }],
  store: true,
  metadata: { project: "onboarding" },
});

const stored = await glexir.chat.completions.retrieve(created.id);
await glexir.chat.completions.update(created.id, { metadata: { project: "onboarding", reviewed: "yes" } });

for await (const completion of glexir.chat.completions.list({ metadata: { project: "onboarding" } })) {
  console.log(completion.id);
}

for await (const message of glexir.chat.completions.messages.list(created.id)) {
  console.log(message.id, message.content);
}

const deleted = await glexir.chat.completions.delete(created.id);
console.log(stored.id, deleted.deleted);
MethodNotes
retrieve(completionId, options?)Returns the ChatCompletion.
update(completionId, body, options?)ChatCompletionUpdateParams is { metadata: Record<string, string> | null }. Metadata is the only field you can change, and it is required (400 without it).
list(query?, options?)ChatCompletionListParams: after?, limit?, metadata? (filter by key/value), model?, order? (asc by default). Returns PagePromise<ChatCompletion>; iterate with for await.
delete(completionId, options?)Returns ChatCompletionDeleted: { id, deleted, object: "chat.completion.deleted" }.
messages.list(completionId, query?, options?)MessageListParams: after?, limit?, order?. Returns PagePromise<ChatCompletionStoreMessage>, a message with id and optional content_parts.

Errors

StatuscodeCause
400unsupported_on_glexirHosted tool, unsupported tool_choice, audio input or output, or web_search_options.
400model_not_foundmodel missing, not a text model, not enabled, or Responses-only (-pro).
400nullEmpty messages, missing metadata on update, or more than 15 metadata keys with store: true.
402credit_balance_exhausted, spend_limit_exceededNot enough credit, or a spend limit reached.
403model_not_priced, tier_not_allowedModel not in the price book, or tier not available to you.
404nullThe stored completion or a referenced file is not yours.
429rate_limit_exceeded, concurrency_limit_exceededToo many requests.

See HTTP error codes and Errors & retries.