Chat completions

One endpoint for five models: a general assistant, an automatic router, and two that answer only from indexed law.

The request and response shape is the OpenAI Chat Completions API, unchanged. If you already have code talking to it, this section is mostly what to expect when the answer isn't what you assumed.

POST/v1/chat/completions

Models

Models has the full catalogue with pricing; this is what to pick between for chat:

ModelWhat it doesVision
larsa-autoReads the request and routes it to one of the models below — Iranian law, Spanish/EU law, or general. Use this when the caller shouldn't have to know the system has more than one backend.
larsa-generalThe general-purpose assistant. Reads documents and images in the same request.
larsa-general-fastThe same weights as larsa-general, served by a different inference engine. An alternative to compare against, not a strictly faster replacement.
larsa-law-irRetrieval-grounded over 117,499 provisions of Iranian law. Answers only from what it retrieves — see system prompts.
larsa-law-esRetrieval-grounded over 835,951 provisions of consolidated Spanish/EU law (BOE). Same grounding behaviour as larsa-law-ir.

larsa-stt and larsa-tts are also served through the gateway but don't take chat requests — see speech to text and text to speech.

Messages and roles

RoleMeaning
systemInstructions that apply to the whole conversation. Optional, and conventionally first. On larsa-law-ir and larsa-law-es a system message you send is dropped and replaced with the platform's own grounding prompt — those two models decide their own instructions so a caller can't route around what they're allowed to answer from.
userWhat the person (or your application, on their behalf) said. content is a string, or — on vision-capable models — an array mixing text and images; see vision.
assistantA prior model reply. Send it back on the next call to continue the conversation — the API itself keeps no history between requests.
toolThe result of a function the model asked to call, paired to the call by tool_call_id. See function calling.

Parameters

ParameterTypeDescription
model
Required
stringOne of the model ids above, or any id your key is scoped to.
messages
Required
array<message>The conversation so far, oldest first.
stream
Optional
booleanSend the reply as server-sent events instead of one JSON object. See streaming.
Default: false
reasoning_effort
Optional
string"none" disables internal reasoning; other values are not enforced. See below.
Default: none
temperature
Optional
numberSampling temperature. Note this engine's default is 0.8, not the 1.0 an OpenAI client assumes if you never set it.
Default: 0.8
top_p
Optional
numberNucleus sampling. Also not OpenAI's default of 1.0.
Default: 0.95
max_tokens
Optional
integerCaps generated tokens. Left unset, generation runs until the model stops on its own or the context window fills. Ignored on `larsa-law-ir` and `larsa-law-es` — those two strip it before forwarding, so a legal answer is never cut off mid-citation.
Default: unlimited
stop
Optional
string | array<string>Up to a few sequences that end generation when produced.
presence_penalty
Optional
numberPushes away from tokens already used at all.
Default: 0
frequency_penalty
Optional
numberPushes away from tokens in proportion to how often they've appeared.
Default: 0
logprobs
Optional
booleanReturn the log-probability of each output token.
Default: false
top_logprobs
Optional
integerCandidates returned per position when logprobs is true.
Default: 20
response_format
Optional
objectConstrain the reply to a JSON shape. See structured output.
tools / tool_choice
Optional
array / stringFunctions the model may call mid-reply. See function calling.

A parameter not in this table isn't rejected — it's dropped before the request reaches the model. See compatibility boundaries.

reasoning_effort: what actually happens

Every model behind this endpoint except larsa-general-fast is the same underlying engine (llama.cpp, serving a Qwen3.6 checkpoint that reasons before it answers), and that engine honours exactly one value of reasoning_effort:

  • `"none"` turns reasoning off outright. The model answers directly, with no hidden thinking pass.
  • Any other value — `"low"`, `"medium"`, `"high"`, or leaving the parameter out entirely — is accepted without error but doesn't bound anything. The model can spend its whole remaining token budget on hidden reasoning_content and stop with finish_reason: "length" and no visible answer at all.

Measured on the same question: "none" answered in about a second with visible text; "low" produced zero visible characters and finish_reason: "length" after about five seconds. There is no working middle setting right now — only off and unbounded.

The unbounded case
{
  "index": 0,
  "message": {
    "role": "assistant",
    "reasoning_content": "The user is asking... [continues for thousands of tokens]",
    "content": ""
  },
  "finish_reason": "length"
}
Set `reasoning_effort: "none"` explicitly whenever you need a guaranteed, visible answer at predictable latency. larsa-law-ir and larsa-law-es default it to "none" for you if you omit it — their retrieved-context prompts made the empty-answer failure common enough to need a built-in fallback. larsa-auto, larsa-general and larsa-general-fast apply no such default: whatever you send, or don't, goes straight to the model.

System prompts

A system message sets behaviour for the whole conversation — tone, role, constraints. There's nowhere the API stores it between calls, so it goes back in on every request the same as every other message. This applies to larsa-auto, larsa-general and larsa-general-fast. On larsa-law-ir and larsa-law-es a system message you send is discarded and replaced — those two build their own from the statute text they retrieve for the question, and honouring a caller-supplied one would mean a request could argue its way around what the model is grounded in.

Multi-turn conversations

The API is stateless: it has no memory of a previous call. "Continuing a conversation" means resending the whole transcript, with the model's own last reply appended as an assistant message before the new user one:

JSON
{
  "model": "larsa-general",
  "messages": [
    {"role": "user", "content": "What's the capital of Spain?"},
    {"role": "assistant", "content": "Madrid."},
    {"role": "user", "content": "And its population?"}
  ],
  "reasoning_effort": "none"
}

The second question only makes sense with the first turn attached — the model has nothing else telling it "its" refers to Madrid. Token cost grows with every turn you resend, since the whole array is billed as input each time; trimming old turns is your application's job, not the API's.

Full example

curl https://api.console.larsa.larsima.com/v1/chat/completions \
  -H "Authorization: Bearer $LARSA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "larsa-general",
    "messages": [
      {"role": "user", "content": "In one paragraph, explain the difference between temperature and top_p."}
    ],
    "reasoning_effort": "none"
  }'
Response
{
  "id": "chatcmpl-9f2a1c3e7b1a4e0daf3b6c2e1f9a7d55",
  "object": "chat.completion",
  "created": 1755878402,
  "model": "larsa-general",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Temperature scales how peaked or flat the probability distribution over the next token is before sampling..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 24,
    "completion_tokens": 96,
    "total_tokens": 120
  }
}

See also

Navigate Open esc Close