Melious

Generate a chat response. OpenAI-compatible in shape, plus Melious-specific routing and environment fields.

Endpoint:

POST /v1/chat/completions

Auth: Bearer token or x-api-key. Requires scope inference.chat.

Example

from openai import OpenAI

client = OpenAI(
    api_key="sk-mel-<YOUR_API_KEY>",
    base_url="https://api.melious.ai/v1",
)

response = client.chat.completions.create(
    model="<MODEL_ID>",
    messages=[
        {"role": "system", "content": "You are concise."},
        {"role": "user", "content": "Name three Hanseatic cities."},
    ],
)
print(response.choices[0].message.content)
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: "sk-mel-<YOUR_API_KEY>",
  baseURL: "https://api.melious.ai/v1",
});

const response = await client.chat.completions.create({
  model: "<MODEL_ID>",
  messages: [
    { role: "system", content: "You are concise." },
    { role: "user", content: "Name three Hanseatic cities." },
  ],
});
console.log(response.choices[0].message.content);
curl https://api.melious.ai/v1/chat/completions \
  -H "Authorization: Bearer sk-mel-<YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<MODEL_ID>",
    "messages": [
      {"role": "system", "content": "You are concise."},
      {"role": "user", "content": "Name three Hanseatic cities."}
    ]
  }'

Request

Core parameters

ParameterTypeDefaultDescription
modelstring—Model ID, optionally with a flavor suffix like :eco. See Routing.
messagesarray—The conversation, oldest first. Each entry has a role and content.
max_tokensintegermodel maxCaps the completion length.
temperaturenumbermodel defaultSampling temperature, [0, 2]. Lower is closer to deterministic. Set this or top_p, not both.
top_pnumber1Nucleus sampling cutoff, [0, 1].
top_kintegerunsetRestrict to top-K tokens (provider-specific).
min_pnumberunsetMinimum-probability tail cut (provider-specific).
frequency_penaltynumber0Penalize repeated tokens, [-2, 2].
presence_penaltynumber0Penalize tokens already present, [-2, 2].
stopstring | arraynullStop sequences.
seedintegernoneDeterministic sampling (best-effort — not all providers honor it).
userstringnoneEnd-user identifier for abuse monitoring.
ninteger1Number of completions, [1, 10].

Streaming

ParameterTypeDefaultDescription
streambooleanfalseEnable SSE streaming.
stream_optionsobjectnullinclude_usage defaults to true: the stream ends with a usage chunk carrying billing_cost and environment_impact. {"include_usage": false} opts out.

See Streamed response for the chunk sequence and Streaming for consumer code.

Tools

ParameterTypeDefaultDescription
toolsarraynullFunction definitions the model may call.
tool_choicestring | object"auto""auto", "none", "required", or {"type": "function", "function": {"name": "..."}}.
parallel_tool_callsbooleanprovider defaultForwarded to the provider when true or false. Absent, null, or non-boolean values are ignored, not rejected. We forward the flag; whether the engine enforces it is the engine's call.

Tool flow and examples: Tool calling.

Structured output

ParameterTypeDefaultDescription
response_formatobjectnull{"type": "json_object"} or {"type": "json_schema", "json_schema": {...}}.

Walkthrough: Structured outputs.

Log probabilities

ParameterTypeDefaultDescription
logprobsbooleanfalseReturn log probabilities. Off by default — turning it on roughly doubles the payload, so we only do that when you ask.
top_logprobsintegerunsetNumber of top alternatives per position, [0, 20].

On a stream, choices[].logprobs rides on the chunks the provider attaches it to — see Streamed response.

Reasoning

ParameterTypeDefaultDescription
reasoning_effortstringmodel default"none", "minimal", "low", "medium", "high", "xhigh", or "max". We fold these to three levels before they reach the model: minimal → low, xhigh and max → high; none turns reasoning off. Only glm-5.3 and glm-5.3-flash receive xhigh/max as sent.
chat_template_kwargsobjectmodel default{"enable_thinking": false} turns reasoning off and true turns it on. If you send reasoning_effort too, it wins. See Switch reasoning on or off.

Switch reasoning on or off

Send reasoning_effort: "none" to turn reasoning off. Any other value turns it on; the table above says how the levels map.

chat_template_kwargs does the same with a boolean: {"enable_thinking": false} turns reasoning off and true turns it on. It's the shape vLLM and SGLang use, and the OpenAI SDKs send it when you pass it through extra_body:

from openai import OpenAI

client = OpenAI(
    api_key="sk-mel-<YOUR_API_KEY>",
    base_url="https://api.melious.ai/v1",
)

response = client.chat.completions.create(
    model="qwen3.6-35b-a3b",
    messages=[{"role": "user", "content": "Name three Hanseatic cities."}],
    extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)

The SDK merges extra_body into the request root, so chat_template_kwargs goes over the wire as a top-level field:

{
  "model": "qwen3.6-35b-a3b",
  "messages": [{"role": "user", "content": "Name three Hanseatic cities."}],
  "chat_template_kwargs": {"enable_thinking": false}
}

If you send both fields, reasoning_effort wins. If you send neither, the model's default applies — some models, such as qwen3.6-35b-a3b, reason by default.

Reasoning tokens bill as output tokens, so turning reasoning off cuts cost and latency. usage.reasoning_tokens is 0 on a response where it's off.

On /v1/responses, use its native form instead: reasoning: {"effort": "none"}. See Responses.

Melious-specific

ParameterTypeDefaultDescription
request_idstringautoClient-provided correlation ID. If omitted, we generate one.
blueprint_idUUIDnoneLoad a vault-stored blueprint (requires X-Vault-Key header).
blueprint_configobjectnoneInline blueprint configuration. Takes precedence over blueprint_id.
variablesobjectnoneOverride blueprint variables.
skill_idsarraynoneLoad vault skills by ID into the request. Requires X-Vault-Key.
skill_configsarraynoneInline skill configurations.

Blueprints and skills are part of the vault-encrypted composition system — most API callers don't need them.

messages

Each entry is an object:

  • role — "system", "developer", "user", "assistant", or "tool". A developer message is treated as a system message, and a name on it is dropped. Blueprint replace and append target the first system or developer message.
  • content — a string, or an array of content parts (for vision).

Vision content parts:

{
  "role": "user",
  "content": [
    {"type": "text", "text": "What's in this image?"},
    {"type": "image_url", "image_url": {"url": "https://example.com/cat.jpg"}}
  ]
}

image_url.url accepts public URLs or base64 data URIs (data:image/jpeg;base64,...). URLs are fetched and re-encoded server-side before inference, so the provider never sees your URL. Model has to support vision — check _meta.capabilities.vision on GET /v1/models/{id}?include_meta=true.

Tool messages:

{
  "role": "tool",
  "tool_call_id": "call_abc",
  "content": "{\"temperature\": 22}"
}

Response

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1699999999,
  "model": "<MODEL_ID>",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hamburg, Lübeck, Bremen.",
        "tool_calls": null
      },
      "finish_reason": "stop",
      "logprobs": null
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 7,
    "total_tokens": 19,
    "cached_tokens": 0,
    "reasoning_tokens": 0,
    "prompt_tokens_details": { "cached_tokens": 0 },
    "completion_tokens_details": { "reasoning_tokens": 0 }
  },
  "system_fingerprint": null,
  "environment_impact": { "energy_kwh": 0.00015, "carbon_g_co2": 0.06, "water_liters": 0.0, "renewable_percent": 100, "pue": 1.2, "provider_id": "melious", "location": "FI" },
  "billing_cost": { "energy": "2.62", "credits": "0.000262", "paid_with": "credits" }
}

For a reasoning model, choices[].message.reasoning_content carries the model's intermediate thinking as a string, alongside content.

choices[].finish_reason

  • stop — model stopped naturally or hit a stop sequence.
  • length — max_tokens hit.
  • tool_calls — model wants to call a tool.
  • content_filter — blocked by provider safety filter.
  • blocked — blocked by a Melious blueprint railguard.
  • blueprint_override — blueprint replied directly, no model call.

usage

Token accounting, OpenAI-shaped plus two Melious-relevant fields:

  • cached_tokens — prompt tokens served from the provider's prefix cache, a subset of prompt_tokens. Billed at the cheaper cache-read rate. Also nested in prompt_tokens_details.cached_tokens.
  • reasoning_tokens — completion tokens the model spent on internal reasoning, a subset of completion_tokens. Also nested in completion_tokens_details.reasoning_tokens. Zero for non-reasoning models.

environment_impact

Melious extension. The request's estimated energy, carbon, and water, plus the public provider that served it. Omitted when the estimate fails or the provider's public identity can't be resolved safely; billing_cost is still present. Field definitions and the method: Environmental impact.

billing_cost

energy is the request's cost in energy units; credits is the EUR equivalent of the same cost — the same cost in two currencies, not a split between balances. Both are populated on every non-streaming response.

paid_with names what actually paid: energy, credits, mixed (both balances), pool (an organization pool), concurrency (covered by a concurrency plan's slots, nothing debited), or free (no charge). See Pricing. Decimals are strings to avoid float drift.

Streamed response

With stream: true, content arrives as chat.completion.chunk events. By default, a successful stream ends with the chunk carrying finish_reason, a separate usage chunk with choices: [], then [DONE], subject to the opt-out and omissions described below:

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1699999999,"model":"<MODEL_ID>","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1699999999,"model":"<MODEL_ID>","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":7,"total_tokens":19,"cached_tokens":0,"reasoning_tokens":0,"prompt_tokens_details":{"cached_tokens":0},"completion_tokens_details":{"reasoning_tokens":0}},"environment_impact":{"energy_kwh":0.00015,"carbon_g_co2":0.06,"water_liters":0.0,"renewable_percent":100,"pue":1.2,"provider_id":"melious","location":"FI"},"billing_cost":{"energy":"2.62","credits":"0.000262","paid_with":"credits"}}

data: [DONE]

The usage chunk is sent unless stream_options.include_usage is false:

  • One usage report. usage that a provider attaches to a content or finish_reason chunk is removed there and sent on the usage chunk. When a provider reports usage more than once, the last report is sent.
  • Built when missing. If the provider reports no usage, the chunk is built from the billed token counts, with id, created, and model taken from earlier chunks.
  • Same shapes. environment_impact and billing_cost sit at the top level, shaped as in the non-streamed response.
  • Omissions. No environment_impact when the estimate fails or the provider's public identity can't be resolved. Neither field when the request can't be settled, the stream fails, or it ends without billing metadata; usage already received is still sent. Nothing further after a disconnect.

With {"include_usage": false}, the provider's stream is forwarded as-is: no extension fields, no built usage chunk, and any provider usage — including usage attached to a content chunk — passes through unchanged. Full case list: Streaming.

A chunk carries choices[].logprobs and choices[].delta.refusal when the provider sent them. Otherwise both keys are absent, not null, so a chunk without them is byte-identical to one from before we forwarded them.

In-stream errors

After the response headers are sent, a failed stream keeps its HTTP 200 and reports the failure inside the body:

data: {"type":"error","error":{"message":"...","type":"server_error","param":null,"code":"server_error"}}

data: [DONE]

The error frame is normally the last data frame before data: [DONE], but a stream may also end unexpectedly without [DONE] — treat that as a failure too. A usage chunk can come before the error frame; it carries no billing_cost or environment_impact, and their absence isn't a zero charge. error.type on the wire is one of server_error, rate_limit_exceeded, billing_error, or invalid_request_error. See Mid-stream failures for retry boundaries and billing.

Once a stream has carried output — text, reasoning, tool calls, a refusal, or token logprobs — a provider failure ends it with this one error frame; we don't fail over to another provider once you've seen output.

Errors

Errors use the OpenAI shape — {"error": {"message", "type", "param", "code"}}. The body carries no request id; read the X-Request-ID response header and quote it to support. These are endpoint-level errors. Account-level throttling uses a flat 429 with code RATE_LIMIT_EXCEEDED; see Errors. Common statuses on this endpoint:

StatustypecodeMeaning
400invalid_request_errorinvalid_request_errorMalformed request — param names the field.
400invalid_request_errormodel_not_capableCapability the model doesn't have (vision, tools, JSON mode).
400invalid_request_errorcontext_length_exceededInput exceeds the model's context window.
400invalid_request_errorcontent_policy_violationRejected by the safety filter.
401authentication_errorinvalid_api_keyMissing or invalid API key.
403authentication_errorauth_insufficient_scopeKey lacks the inference.chat scope.
404invalid_request_errormodel_not_foundUnknown model ID.
429rate_limit_exceededrate_limit_exceededThrottled — back off per Retry-After.
429billing_errorbilling_insufficient_balance, insufficient_quotaNo eligible balance — not a throttle.
503server_errorserver_error, provider_error, timeoutTransient — retry with backoff.

For endpoint-level 429s, type distinguishes throttling from billing; the account limiter uses the flat code above.

When streaming, a failure after the stream has started arrives as an in-stream error frame rather than this envelope — see Streaming.

Full tables and retry guidance: Errors.

Streaming • Tool calling • Vision • Structured outputs • Routing.

On this page