Create chat completion

POST /v1/chat/completions

Creates a model response for the given chat conversation. OpenAI Chat Completions compatible.

When stream is false (the default), the response is a single JSON chat.completion object (application/json).

When stream is true, the response is a text/event-stream of server-sent events. Each event’s data: field carries one chat.completion.chunk JSON object. The stream is terminated by a final data: [DONE] sentinel, which is a literal marker and not valid JSON.

Reasoning is off by default. Set reasoning_effort to low, medium or high to have the model think before it answers; the reasoning is returned separately from the answer, in choices[].message.reasoning_content (or choices[].delta.reasoning_content when streaming). See x-springboards-reasoning.

Unsupported or unknown request fields are passed through to the upstream inference endpoint unchanged (they are not rejected by the gateway).

The gateway is a drop-in replacement for OpenAI’s Chat Completions API: point any OpenAI SDK at https://api.springboards.ai/v1 and use your Springboards API key.

Reasoning

The model can think before it answers. That thinking costs latency and completion tokens, so it is off by default — set reasoning_effort when a request is worth it:

reasoning_effortBehaviour
none (default)Answers directly. No reasoning_content in the response.
lowA short pass. Cheapest level that still deliberates.
mediumA fuller pass, for multi-step problems.
highThe longest pass, for hard reasoning and analysis.

When the effort is anything but none, the reasoning comes back separately from the answer — in choices[].message.reasoning_content, or choices[].delta.reasoning_content while streaming. It is billed as completion tokens and counts against your TPM limit.

Two request forms set the effort and are treated as equivalent, so use whichever your client makes easiest:

{"reasoning_effort": "high"}
{"reasoning": {"effort": "high"}}

If both are present, reasoning_effort wins. Any other value — including a level the API doesn’t recognise — is treated as none, so the model only thinks when a request asks it to by name.

Request body

Content type: application/json

FieldTypeRequiredDescription
modelstringYesID of the model to use (alias or dated version).
messagesarray of objectYesThe conversation so far, as a list of messages.
chat_template_kwargsobjectNoSpringboards extension: key/value pairs forwarded to the upstream model’s chat template. See x-springboards-chat-template-kwargs.
frequency_penaltynumberNoPenalty between -2 and 2 for tokens based on their frequency so far.
max_completion_tokensintegerNoUpper bound on the number of tokens generated for the completion.
max_tokensintegerNoDeprecated. Maximum number of tokens to generate. Superseded by max_completion_tokens.
nintegerNoNumber of completions to generate for each prompt.
presence_penaltynumberNoPenalty between -2 and 2 for tokens based on whether they appear so far.
reasoningobjectNoObject form of reasoning_effort, for clients that send OpenAI Responses-style options. Equivalent to the reasoning_effort field; if both are present, reasoning_effort wins.
reasoning_effortstring (none, low, medium, high)NoHow much internal reasoning the model does before it answers. Defaults to “none”: thinking is off unless a request asks for it. Reasoning is returned separately from the answer, in message.reasoning_content (or delta.reasoning_content when streaming). See x-springboards-reasoning.
seedintegerNoBest-effort deterministic sampling seed.
stoparray of stringNoUp to 4 sequences where the API stops generating further tokens.
streambooleanNoIf true, partial deltas are streamed as server-sent events terminated by a [DONE] sentinel.
stream_optionsobjectNoOptions that apply only when stream is true.
temperaturenumberNoSampling temperature between 0 and 2.
top_pnumberNoNucleus sampling probability mass.
userstringNoStable identifier for the end user, for abuse monitoring.

messages[]

FieldTypeRequiredDescription
rolestring (system, user, assistant, tool)YesThe role of the message author.
contentstringYesThe contents of the message.
namestringNoOptional name to disambiguate participants with the same role.

reasoning

FieldTypeRequiredDescription
effortstring (none, low, medium, high)NoHow much internal reasoning the model does before it answers.

stream_options

FieldTypeRequiredDescription
include_usagebooleanNoIf true, a final chunk carrying token usage for the whole request is emitted before the [DONE] sentinel. Streamed responses omit usage otherwise.

Fields not listed above are accepted and passed through to the upstream model unchanged.

Responses

200

A chat completion. Returned as a single JSON object, or as an SSE stream when stream=true.

Content type: application/json

FieldTypeRequiredDescription
idstringYesUnique identifier for the completion.
objectstringYesThe object type, always “chat.completion”.
createdintegerYesUnix timestamp (seconds) of when the completion was created.
modelstringYesThe model ID the request asked for, echoed back — the alias or dated ID as sent, so it can be reused on the next request.
choicesarray of objectYesThe list of completion choices.
usageobjectNoToken usage statistics for the request.

choices[]

FieldTypeRequiredDescription
indexintegerYesThe index of this choice in the list.
messageobjectYesThe generated message.
finish_reasonstring (stop, length, content_filter, tool_calls)YesWhy generation stopped.

choices[].message

FieldTypeRequiredDescription
rolestringYesThe role of the author, always “assistant”.
contentstringYesThe contents of the message.
reasoning_contentstringNoThe model’s internal reasoning, present only when reasoning_effort is something other than “none”.

usage

FieldTypeRequiredDescription
prompt_tokensintegerYesTokens in the prompt.
completion_tokensintegerYesTokens in the generated completion.
total_tokensintegerYesTotal tokens used (prompt + completion).

Streaming (text/event-stream)

Each server-sent event is a bare data: line carrying one JSON payload. The stream is terminated by a final data: [DONE] sentinel — a literal marker, not JSON:

data: {"id":"chatcmpl-123","object":"chat.completion.chunk",...}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk",...}

data: [DONE]

Event payload:

FieldTypeRequiredDescription
idstringYesUnique identifier for the completion; shared across all chunks.
objectstringYesThe object type, always “chat.completion.chunk”.
createdintegerYesUnix timestamp (seconds) of when the completion was created.
modelstringYesThe model ID the request asked for, echoed back.
choicesarray of objectYesThe list of streamed choice deltas. Empty on the final usage chunk.
usageobjectNoToken usage for the whole request. Sent on a final chunk only when the request set stream_options.include_usage.

choices[]

FieldTypeRequiredDescription
indexintegerYesThe index of this choice in the list.
deltaobjectYesThe incremental message content for this chunk.
finish_reasonstring (stop, length, content_filter, tool_calls)YesWhy generation stopped, or null while streaming.

choices[].delta

FieldTypeRequiredDescription
contentstringNoThe token(s) appended by this chunk.
reasoning_contentstringNoThe reasoning token(s) appended by this chunk. Reasoning streams before content, and only when reasoning_effort is something other than “none”.
rolestringNoPresent on the first chunk of a choice.

usage

FieldTypeRequiredDescription
prompt_tokensintegerYesTokens in the prompt.
completion_tokensintegerYesTokens in the generated completion.
total_tokensintegerYesTotal tokens used (prompt + completion).

400

The request body was malformed or missing the required model field.

Content type: application/json

FieldTypeRequiredDescription
errorobjectYesThe failure.

error

FieldTypeRequiredDescription
messagestringYesHuman-readable description of the failure.
typestringYesOpenAI error taxonomy value.
paramstringYesThe request parameter at fault, when one applies.
codestringYesMachine-readable error code, when one applies.

401

The API key is missing, malformed, unknown or revoked (code: invalid_api_key).

Content type: application/json

FieldTypeRequiredDescription
errorobjectYesThe failure.

error

FieldTypeRequiredDescription
messagestringYesHuman-readable description of the failure.
typestringYesOpenAI error taxonomy value.
paramstringYesThe request parameter at fault, when one applies.
codestringYesMachine-readable error code, when one applies.

404

The requested model does not exist.

Content type: application/json

FieldTypeRequiredDescription
errorobjectYesThe failure.

error

FieldTypeRequiredDescription
messagestringYesHuman-readable description of the failure.
typestringYesOpenAI error taxonomy value.
paramstringYesThe request parameter at fault, when one applies.
codestringYesMachine-readable error code, when one applies.

413

The request body exceeds the 5 MiB limit.

Content type: application/json

FieldTypeRequiredDescription
errorobjectYesThe failure.

error

FieldTypeRequiredDescription
messagestringYesHuman-readable description of the failure.
typestringYesOpenAI error taxonomy value.
paramstringYesThe request parameter at fault, when one applies.
codestringYesMachine-readable error code, when one applies.

429

Rate limit or quota exhausted. code is rate_limit_exceeded when the workspace’s requests- or tokens-per-minute bucket is empty — retry after the Retry-After header — or insufficient_quota when the workspace is out of billing quota, which retrying will not fix.

Content type: application/json

FieldTypeRequiredDescription
errorobjectYesThe failure.

error

FieldTypeRequiredDescription
messagestringYesHuman-readable description of the failure.
typestringYesOpenAI error taxonomy value.
paramstringYesThe request parameter at fault, when one applies.
codestringYesMachine-readable error code, when one applies.

502

The upstream inference endpoint could not be reached. Retryable.

Content type: application/json

FieldTypeRequiredDescription
errorobjectYesThe failure.

error

FieldTypeRequiredDescription
messagestringYesHuman-readable description of the failure.
typestringYesOpenAI error taxonomy value.
paramstringYesThe request parameter at fault, when one applies.
codestringYesMachine-readable error code, when one applies.

503

The API key could not be validated right now. Transient and retryable; the key is not at fault.

Content type: application/json

FieldTypeRequiredDescription
errorobjectYesThe failure.

error

FieldTypeRequiredDescription
messagestringYesHuman-readable description of the failure.
typestringYesOpenAI error taxonomy value.
paramstringYesThe request parameter at fault, when one applies.
codestringYesMachine-readable error code, when one applies.

Examples

Basic request

curl https://api.springboards.ai/v1/chat/completions \
  -H "Authorization: Bearer $SPRINGBOARDS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flint-alpha",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

Streaming

curl -N https://api.springboards.ai/v1/chat/completions \
  -H "Authorization: Bearer $SPRINGBOARDS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flint-alpha",
    "messages": [{"role": "user", "content": "Hello!"}],
    "stream": true
  }'

Reasoning

curl https://api.springboards.ai/v1/chat/completions \
  -H "Authorization: Bearer $SPRINGBOARDS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flint-alpha",
    "messages": [{"role": "user", "content": "How many r's are in strawberry?"}],
    "reasoning_effort": "high"
  }'
# -> choices[0].message.reasoning_content holds the thinking,
#    choices[0].message.content holds the answer.

OpenAI Python SDK

from openai import OpenAI

client = OpenAI(
    base_url="https://api.springboards.ai/v1",
    api_key=os.environ["SPRINGBOARDS_API_KEY"],
)
completion = client.chat.completions.create(
    model="flint-alpha",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(completion.choices[0].message.content)

Notes

chat_template_kwargs is a Springboards (non-OpenAI) extension. Its key/value pairs are forwarded verbatim to the upstream model’s chat template, allowing per-request template variables that OpenAI’s schema has no field for.

Reasoning effort accepts none, low, medium or high, and defaults to none — the model answers directly unless a request asks it to think. Higher levels trade latency and tokens for more deliberation; reasoning tokens are billed as completion tokens and count against the workspace’s TPM limit.

Two request forms set the effort, and they are equivalent \u2014 the gateway normalises whichever one it receives before calling the model:

{"reasoning_effort": "high"}
{"reasoning": {"effort": "high"}}

reasoning_effort wins over reasoning.effort when both are present. Only a recognised level turns reasoning on: a missing, null or unrecognised value resolves to none, so the model never picks a thinking level of its own.