Quickstart
Mortar speaks the OpenAI chat-completions API, so you can use the official OpenAI SDKs pointed at Mortar. In a few minutes you'll create an API key, send one request and stream a reply.
Create an API key
- Sign in and open API keys in your settings.
- Create a key and give it a name you'll recognise later, such as
quickstart. It expires in 30 days unless you choose otherwise. - Copy the key. It starts with
mk_live_, and Mortar shows it only once.
Creating keys needs the Admin or Owner role in your organization. Authentication explains how keys are stored, how they expire, and how to rotate and revoke them.
Keep the key out of your code. Export it in the shell you'll run the examples from:
export MORTAR_API_KEY="mk_live_your_key_here"Install an SDK
Skip this step if you'll use curl.
pip install openainpm install openaiSend a request
Every example sends the same request: one user message to Qwen/Qwen2.5-7B-Instruct, the model this deployment serves. The base URL is https://api.mortar.one/v1.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.mortar.one/v1",
api_key=os.environ["MORTAR_API_KEY"],
)
completion = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=[{"role": "user", "content": "Explain prefix caching in one sentence."}],
stream=False,
)
print(completion.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.mortar.one/v1",
apiKey: process.env.MORTAR_API_KEY,
});
const completion = await client.chat.completions.create({
model: "Qwen/Qwen2.5-7B-Instruct",
messages: [{ role: "user", content: "Explain prefix caching in one sentence." }],
stream: false,
});
console.log(completion.choices[0].message.content);curl https://api.mortar.one/v1/chat/completions \
-H "Authorization: Bearer $MORTAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen2.5-7B-Instruct",
"messages": [{"role": "user", "content": "Explain prefix caching in one sentence."}],
"stream": false
}'Pass stream explicitly. When a request leaves it out, Mortar streams the reply, and the OpenAI SDKs leave it out unless you set it. Without stream=False (Python) or stream: false (TypeScript), the SDK receives an event stream where it expects JSON.
The reply is a chat completion object. The answer is in choices[0].message.content, and usage counts the tokens you're billed for:
{
"id": "chatcmpl-5d0e8f6a2b4c4e1f9a3b7c6d",
"object": "chat.completion",
"created": 1767225600,
"model": "Qwen/Qwen2.5-7B-Instruct",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Prefix caching keeps the attention state for a prompt's opening tokens, so a request that starts like an earlier one skips recomputing them."
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 19,
"completion_tokens": 29,
"total_tokens": 48
}
}Stream the reply
Set stream to true and Mortar sends the reply as server-sent events while it is generated, so you can show the first words before the last are written.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.mortar.one/v1",
api_key=os.environ["MORTAR_API_KEY"],
)
stream = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=[{"role": "user", "content": "Explain prefix caching in one sentence."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta if chunk.choices else None
if delta and delta.content:
print(delta.content, end="", flush=True)
print()import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.mortar.one/v1",
apiKey: process.env.MORTAR_API_KEY,
});
const stream = await client.chat.completions.create({
model: "Qwen/Qwen2.5-7B-Instruct",
messages: [{ role: "user", content: "Explain prefix caching in one sentence." }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
process.stdout.write("\n");curl -N https://api.mortar.one/v1/chat/completions \
-H "Authorization: Bearer $MORTAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen2.5-7B-Instruct",
"messages": [{"role": "user", "content": "Explain prefix caching in one sentence."}],
"stream": true
}'With curl you see the raw stream: one chat.completion.chunk per event, ending with [DONE]. The SDKs parse these frames for you.
data: {"id":"chatcmpl-5d0e8f6a2b4c4e1f9a3b7c6d","object":"chat.completion.chunk","created":1767225600,"model":"Qwen/Qwen2.5-7B-Instruct","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-5d0e8f6a2b4c4e1f9a3b7c6d","object":"chat.completion.chunk","created":1767225600,"model":"Qwen/Qwen2.5-7B-Instruct","choices":[{"index":0,"delta":{"content":"Prefix caching keeps"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-5d0e8f6a2b4c4e1f9a3b7c6d","object":"chat.completion.chunk","created":1767225600,"model":"Qwen/Qwen2.5-7B-Instruct","choices":[{"index":0,"logprobs":null,"finish_reason":"stop"}]}
data: [DONE]Stream responses covers the frame format in full, including usage reporting, cancellation and errors that arrive mid-stream.
Next steps
- Make repeated requests cheaper and faster with cache-friendly prompts.
- Look up every field and error in the chat completions reference.
- Compare prices and context windows in the model catalog.