Skip to main content
POST /v1/chat/completions searches your project’s indexes for the user’s question, adds what it finds to the prompt, and returns the reply in OpenAI’s shape. Any OpenAI client works: change the base URL and the key.
Base URL

Authentication

Send the project id and project key from the Moss portal as one bearer token:

Request

The body is an OpenAI chat completion request. usage.prompt_tokens includes the retrieved facts. A reply that reached the model carries X-Moss-Request-Id: include it when you report a problem. The x-ratelimit-limit-*, x-ratelimit-remaining-* and x-ratelimit-reset-* headers, for requests and, on moss, tokens, show how much of the project’s limits is left.

Streaming

The last chunk before data: [DONE] has empty choices and the whole reply’s usage; no other chunk carries it. {"include_usage": false} in stream_options leaves it out. Check choices before reading choices[0], as the examples below do.

Examples

The Python and JavaScript examples below use OpenAI’s own clients. Every Moss SDK also has its own client for this endpoint: Python, JavaScript, Swift, Android, Elixir, Browser, and C.

Models

Retrieval works the same for every model. A vendor model without X-Moss-Provider-Key, or any other model name, returns 400. The provider key is sent only to that vendor and is never stored.

Limits

Per project: On moss the 16,384 tokens are the model’s whole context: the prompt, the retrieved facts and the reply share them, so leave room for max_tokens. A prompt over it is 400 with type invalid_request_error and code: "context_length_exceeded". Over a per-minute limit the response is 429 with type requests or tokens and code: "rate_limit_exceeded". When Moss is at capacity it is 429 with type capacity and code: "server_overloaded". Both carry Retry-After, and the OpenAI SDKs retry on their own. A paused project gets 429 with code: "usage_limit_exceeded" and stays refused until it is unpaused in the portal.
429 - Too Many Requests

Errors

Errors use OpenAI’s {"error": {"message", "type", "code"}} shape. A failure after a stream has started arrives as a final data: frame carrying error instead of choices, then data: [DONE].

Tool calls

tools, tool_choice and parallel_tool_calls take OpenAI’s shapes and go to the model. Your code runs the tools. A tools value that is not a list of objects returns 400. A streamed reply sends each call in pieces in delta.tool_calls, with index, id, function.name and function.arguments, then a chunk with finish_reason tool_calls. A reply without stream has the calls joined in choices[0].message.tool_calls, with the same finish_reason. Send the assistant message back unchanged, then one tool message per call, and call again:
A tool call can carry fields beyond OpenAI’s, such as Gemini’s extra_content. Keep them: the model needs them on the next turn.

MCP servers

A tools entry of type mcp names an MCP server. Moss Inference connects to it, offers its tools to the model, runs the calls the model makes, and streams the final answer. One request can hold your own tools and MCP servers together.
MCP calls are not added to the message history. Keep what you need from the tool steps in your own messages. A request with MCP servers can run for a few minutes.

Tool steps

A stream carries one extra chunk before each MCP call and one after it, with an empty delta and a moss_tool_step:
type is call before the tool runs, with its arguments, and result after it, with is_error, duration_ms and output. Both have the same id, the server_label and the tool’s name. A reply without stream lists the steps in order in a top-level moss_tool_steps array. OpenAI clients ignore both fields.

MCP errors

A tool may already have changed data when a call fails after it, so Moss Inference never retries that call. Without stream, it returns 424 with code failed_after_tool_call, the moss_tool_steps that ran, and the header x-should-retry: false. On a stream, it is an error event after a step, which the Moss SDKs report with the code failed_after_tool_call. Do not replay such a call.