Chat completions

POST/v1/chat/completions

Answer a conversation in the OpenAI chat-completions shape, through memory, routing, connector tools and agent mode, streamed or in one reply.

Open Memtro

The main endpoint. It takes the OpenAI chat-completions request, so any OpenAI-compatible client works unchanged, and runs it through Memtro: memories retrieved and put in front of the model, the model chosen by routing or named by you, Memtro's memory and connector tools available to it, and in agent mode a multi-step investigation before the answer. Facts from the exchange are learned afterwards, into the memory the key may write.

Set stream: true for server-sent events. A request can run for up to five minutes, which agent runs need; keep client timeouts generous.

Example

Against https://platform.memtro.com, with your key in MEMTRO_API_KEY.

curl https://platform.memtro.com/v1/chat/completions \
  -H "Authorization: Bearer $MEMTRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "messages": [{"role": "user", "content": "Who owns the billing migration?"}],
    "memtro": {"mode": "agent"}
  }'

A non-streaming reply.

{
  "id": "chatcmpl-k3Vq…",
  "object": "chat.completion",
  "created": 1794470400,
  "model": "anthropic/claude-opus-5",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Priya owns the billing migration. BIL-142 moved to her on 3 November." },
      "finish_reason": "stop",
      "logprobs": null
    }
  ],
  "usage": {
    "prompt_tokens": 4210,
    "completion_tokens": 188,
    "total_tokens": 4398,
    "prompt_tokens_details": { "cached_tokens": 3072 }
  },
  "memtro": {
    "mode": "agent",
    "engine": "native",
    "routing": {
      "requested": "auto",
      "model": "anthropic/claude-opus-5",
      "complexity": 3,
      "method": "heuristic",
      "reason": "…",
      "fallbacks": ["…"],
      "kind": "general"
    },
    "citations": [
      { "system": "linear", "label": "BIL-142 Billing migration", "url": "https://linear.app/…" }
    ],
    "tools": [
      { "tool": "linear_search", "input": { "query": "billing migration" }, "ok": true, "summary": "3 issues" }
    ]
  }
}

Authentication

An API key, as Authorization: Bearer or x-api-key. The key's scope is a ceiling on what the request reaches.

  • Every reply, errors included, carries x-request-id and request-id headers with the same id, starting chatcmpl-. Quote it to support.
  • Browsers may call it from any origin: it answers CORS preflights and allows the Authorization, x-api-key and Anthropic version headers.

Request body

JSON, with Content-Type: application/json.

modelstringOptional

A model id or routing id; see Model ids. A :agent or :chat suffix forces the mode. Under the organisation's model lock a named model is answered by memtro instead, without an error.

Default:

memtro

messagesarray of objectsRequired

The conversation, at least one message.

6 fields of messages
rolestringRequired

Who said it.

One of system, developer, user, assistant, tool or function.

contentstring or array of objects or nullOptional

Text, or an array of content parts such as {"type": "text", "text": …} and {"type": "image_url", "image_url": {"url": …}}. An image URL must be a data: URI or an absolute http(s) URL, or the request is refused with a 400. Parts with no equivalent on the model's wire are dropped.

namestringOptional

A name for the participant.

tool_callsarray of objectsOptional

On an assistant turn, the calls it made to your tools: id, type and function (name, arguments).

tool_call_idstringOptional

On a tool turn, the call this result answers.

cache_controlobjectOptional

A cache breakpoint, {"type": "ephemeral"}: everything up to here is a stable prefix. Only Anthropic models take explicit breakpoints; elsewhere it is ignored.

streambooleanOptional

Answer as server-sent events. See Streaming.

Default:

false

stream_optionsobjectOptional

Stream settings.

1 field of stream_options
include_usagebooleanOptional

Add a final chunk with choices: [] and usage before [DONE].

temperaturenumberOptional

Sampling temperature, passed to the provider.

top_pnumberOptional

Nucleus sampling, passed to the provider.

max_tokensintegerOptional

A ceiling on the answer's tokens; a positive integer.

max_completion_tokensintegerOptional

The same ceiling under its newer name; wins over max_tokens.

stopstring or array of stringsOptional

Where to stop generating.

toolsarray of objectsOptional

Your own tools. When the model calls one, the reply carries tool_calls for you to run, and you send the results back as tool messages. Memtro's own tools are separate and need no declaring. A request that declares tools runs in chat mode unless it asks for agent. With claude-code/* and codex/* models your tools are bridged into the CLI run.

2 fields of tools
type"function"Required

Always function.

functionobjectRequired

The tool.

3 fields of function
namestringRequired

Its name.

descriptionstringOptional

What it does, for the model.

parametersobjectOptional

Its arguments, as JSON Schema.

tool_choicestring or objectOptional

none, auto, required, or {"type": "function", "function": {"name": …}} to force one tool.

reasoning_effortstringOptional

How hard to think. high, xhigh and max ask for deep thinking, medium and low for standard, and the provider's own thinking setting is set to match. Any other value, none included, leaves the provider's default.

response_formatobjectOptional

The shape the answer must take, handed to the provider's own structured-output setting. Any other type is refused with unsupported_parameter.

2 fields of response_format
typestringOptional

text asks for nothing; json_object for some JSON object; json_schema for the schema below.

One of text, json_object or json_schema.

json_schemaobjectOptional

For json_schema. The same keys sent flat beside type are read too.

3 fields of json_schema
namestringOptional

A name for the schema.

Default:

response

descriptionstringOptional

What it describes.

schemaobjectRequired

A JSON Schema object.

nintegerOptional

Only 1 is accepted: one choice is returned per request, and n above 1 is refused with unsupported_parameter rather than answered with one choice.

logprobs, top_logprobsanyOptional

Refused with unsupported_parameter: token probabilities are not returned.

user, store, metadata, seed, frequency_penalty, presence_penalty, logit_bias, parallel_tool_callsanyOptional

Accepted and ignored. See Compatibility.

memtroobjectOptional

Memtro's options; see the memtro object. brain is accepted as an older name.

11 fields of memtro
modestringOptional

agent runs the multi-step harness: plan, query every relevant system, cross-reference, answer once. A :agent or :chat suffix on the model id does the same. See Agent mode.

One of chat or agent.

Default:

The organisation's default mode; chat when the request declares its own tools

memorystringOptional

Where facts learned from this exchange are stored, and a ceiling the key can lower but the request cannot raise: an organisation key never reads or writes personal memory, and a personal key set to "mine only" never reaches the organisation's. off stores nothing.

One of org, personal or off.

Default:

org when the key belongs to an organisation, otherwise personal

retrievebooleanOptional

Put relevant memories and graph context in front of the model.

Default:

true

toolsboolean or "memory"Optional

Memtro's own tools: true for the memory tools and your connector tools, "memory" for the memory tools alone, false for none.

Default:

true

show_progressbooleanOptional

In agent mode, stream a text copy of the tool log as reasoning_content. The structured memtro.activity events are sent either way.

Default:

The organisation's agent setting, otherwise true

show_thinkingbooleanOptional

Return the model's thinking on wires that have a block for it.

Default:

Whatever the client asked for on its own wire

cachebooleanOptional

Serve identical connector tool calls from the short-lived result cache.

Default:

true

as_ofstringOptional

A calendar date, YYYY-MM-DD: answer from memory as it stood at the end of that day. Retrieval and the memory tools report what was believed then, and nothing from the exchange is learned. Anything that is not a real date is refused with invalid_as_of. See Time travel.

sessionstringOptional

An opaque id for this conversation, 1 to 200 characters, so repeated turns are recognised as one session: it groups usage and lets retrieval be reused between turns.

projectstringOptional

The repository or project this session is working in, 1 to 200 characters (for example owner/repo), so memory about it is preferred. Ignored when the graph has never heard of it.

verifybooleanOptional

Check the drafted answer against the retrieved context with a second model call before returning it, dropping claims nothing in the context supports. One extra model call per answer.

Default:

false

Response

200application/json

A chat.completion, plus a memtro object when there is something to report.

idstringOptional

chatcmpl-…, the same id as the x-request-id header.

object"chat.completion"Optional

Always chat.completion.

createdintegerOptional

Unix time, in seconds.

modelstringOptional

The model that was picked.

choicesarray of objectsOptional

Exactly one choice.

4 fields of choices
indexintegerOptional

Always 0.

messageobjectOptional

The answer.

3 fields of message
role"assistant"Optional

Always assistant.

contentstring or nullOptional

The text, or null when the model only called your tools.

tool_callsarray of objectsOptional

Calls to your tools, each with id, type: "function" and function (name, arguments as a JSON string).

finish_reasonstringOptional

Why it ended.

One of stop, length, content_filter or tool_calls.

logprobsnullOptional

Always null.

usageobjectOptional

Tokens.

4 fields of usage
prompt_tokensintegerOptional

Input tokens.

completion_tokensintegerOptional

Output tokens.

total_tokensintegerOptional

The two added.

prompt_tokens_detailsobjectOptional

cached_tokens: input the provider served from its cache.

memtroobjectOptional

Mode, routing, citations, grounding and Memtro's tool calls; see What comes back.

200text/event-stream

With stream: true: chat.completion.chunk events, then data: [DONE]. See Streaming.

Streaming

Each event is a data: line holding a chat.completion.chunk. The first chunk opens the assistant turn and carries memtro with the mode and the routing decision. Text arrives as delta.content, the model's thinking and agent progress as delta.reasoning_content, and calls to your tools as delta.tool_calls. Each of Memtro's own tool calls sends a memtro.activity event when it starts and when it finishes; with show_progress off those come on chunks with choices: [] and no text. A chunk with choices: [] then carries the closing memtro (Memtro's tool calls, and answered_by when another model answered), a chunk carries finish_reason, stream_options.include_usage adds a usage chunk, and data: [DONE] ends the stream.

If the run fails after the stream has started, the status is already 200: an error chunk is sent instead, and the stream closes without [DONE]. Treat a stream that ends without [DONE] as failed.

data: {"id":"chatcmpl-k3Vq…","object":"chat.completion.chunk","created":1794470400,"model":"anthropic/claude-opus-5","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"logprobs":null}],"memtro":{"mode":"agent","engine":"native","routing":{"requested":"auto","model":"anthropic/claude-opus-5","complexity":3,"method":"heuristic","reason":"…","fallbacks":["…"],"kind":"general"}}}

data: {…,"choices":[{"index":0,"delta":{"reasoning_content":"▸ linear_search(query=\"billing migration\")"},"finish_reason":null,"logprobs":null}],"memtro":{"activity":{"id":"call_1","tool":"linear_search","input":{"query":"billing migration"},"phase":"start"}}}

data: {…,"choices":[{"index":0,"delta":{"reasoning_content":"\n  ✓ 3 issues"},"finish_reason":null,"logprobs":null}],"memtro":{"activity":{"id":"call_1","tool":"linear_search","phase":"done","ok":true,"summary":"3 issues"}}}

data: {…,"choices":[{"index":0,"delta":{"content":"Priya owns the billing migration"},"finish_reason":null,"logprobs":null}]}

data: {…,"choices":[],"memtro":{"tools":[{"tool":"linear_search","input":{"query":"billing migration"},"ok":true,"summary":"3 issues"}]}}

data: {…,"choices":[{"index":0,"delta":{},"finish_reason":"stop","logprobs":null}]}

data: {…,"choices":[],"usage":{"prompt_tokens":4210,"completion_tokens":188,"total_tokens":4398,"prompt_tokens_details":{"cached_tokens":3072}}}

data: [DONE]

# A failure after the stream started: no [DONE] follows.
data: {"error":{"message":"…","type":"server_error","param":null,"code":null}}

Errors

In the OpenAI envelope, {"error": {"message", "type", "param", "code"}}. What each code means and what to do about it is in the error catalogue.

StatusCodeWhen
400none

The body failed validation.

400unsupported_parameter

n above 1, logprobs, top_logprobs, or a response_format type other than text, json_object or json_schema.

400invalid_as_of

memtro.as_of is not a calendar date.

400routing_unavailable

auto found no usable ladder.

400provider_not_configured

No key for the provider the model needs.

400invalid_provider_base_url

An OpenAI-compatible endpoint's base URL cannot be used: not a URL, not https://, a user name or password in it, or a port not accepted.

400provider_base_url_not_allowed

An OpenAI-compatible endpoint's host is not approved for the organisation, is private or internal, does not resolve, or redirected, whether refused before the request or during it.

401invalid_api_key

The key is missing, malformed, revoked or expired.

402subscription_inactive

The organisation has no active subscription.

404model_not_found

Unknown model id.

429allowance_exhausted

The month's allowance for the request's level is spent.

provider'supstream_error

The provider returned an error.

503engine_unavailable

The CLI a claude-code/* or codex/* model needs is not installed.

500none

An internal error.

Notes

Model lock. Organisations start with the model lock on: a request naming a specific model is answered by memtro instead of being refused, and when the request is routed, memtro.routing.locked is true. GET /v1/models then lists only the routing ids and memtro.

Client tools with CLI models. Your tools work with claude-code/* and codex/* models too: they are bridged into the CLI run and come back as tool_calls. When you send the results, the run carries on where it stopped.

Where agents remember your company

Sign in, add a provider key, create an API key and point your tools at Memtro. It takes about five minutes.

7-day free trial · card on file, nothing charged until it ends · cancel any time