Quickstart · LLM mocking
AvailableLast verified
Mock your first LLM call in two minutes
Create an LLM workspace, copy one base URL, and change only the base URL of the SDK your application already uses. Every request is then answered by the first matching fixture instead of a paid, nondeterministic provider.
In this guide
- Create an LLM mock and copy its base URL
- Point any provider SDK at the mock
- Add a fixture and see it win
- Run the same file offline with dotmock serve
Prerequisites
- An LLM DotMock workspace, or a local dotmock.yaml served by dotmock serve
- The workspace ID in $API_ID and its runtime URL in $MOCK_URL (SDK base URL $MOCK_URL/v1 for OpenAI-compatible clients)
On this page
Create an LLM mock and copy the base URL
Choose New workspace, then LLM API. The workspace opens on its fixtures and shows the runtime URL; export it as $MOCK_URL. The same host serves every supported provider shape, so one mock can answer OpenAI, Anthropic, Gemini, Bedrock, Azure OpenAI, Ollama, and Cohere clients at the same time.
OpenAI-compatible SDKs take $MOCK_URL/v1 as their base URL because they append /chat/completions or /responses. Anthropic, Gemini, and Ollama SDKs take $MOCK_URL because they append their own /v1/messages, /v1beta/models/…, or /api/chat paths.
export MOCK_URL="https://<your-llm-mock-host>" # copied from the workspace
export OPENAI_BASE_URL="$MOCK_URL/v1"
export ANTHROPIC_BASE_URL="$MOCK_URL"
export OPENAI_API_KEY=dotmock ANTHROPIC_API_KEY=dotmock # any non-empty valueSend a request with curl
A fresh LLM workspace has no fixtures, so the first call proves routing: it returns HTTP 404 with the error code no_fixture_matched. Once a fixture matches, the response is provider-shaped. This call then returns an OpenAI chat.completion object with choices, finish_reason, and usage, plus x-dotmock-fixture-id and x-dotmock-fixture-name response headers naming the winner.
curl "$MOCK_URL/v1/chat/completions" \
-H 'content-type: application/json' \
-H 'X-Dotmock-Session: quickstart' \
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hello"}]}'Point the SDK you already use at the mock
Only the base URL and key change. Tool definitions, streaming flags, response parsing, and retry logic stay exactly as in production, which is the code you actually want to test. Optional default headers pin a session for sequence counters and a seed for reproducible randomness.
from openai import OpenAI
client = OpenAI(
base_url=f"{MOCK_URL}/v1",
api_key="dotmock",
default_headers={"X-Dotmock-Session": "test-1", "X-Dotmock-Seed": "42"},
)
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "hello"}],
)
print(resp.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: `${process.env.MOCK_URL}/v1`,
apiKey: "dotmock",
defaultHeaders: { "X-Dotmock-Session": "test-1", "X-Dotmock-Seed": "42" },
});
// Chat Completions and the Responses API are both served.
const chat = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "hello" }],
});
const response = await client.responses.create({ model: "gpt-4o-mini", input: "hello" });from anthropic import Anthropic
client = Anthropic(base_url=MOCK_URL, api_key="dotmock") # SDK appends /v1/messages
msg = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": "hello"}],
)
print(msg.content[0].text)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({ baseURL: process.env.MOCK_URL, apiKey: "dotmock" });
const msg = await client.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 1024,
messages: [{ role: "user", content: "hello" }],
});from google import genai
from google.genai import types
client = genai.Client(
api_key="dotmock",
http_options=types.HttpOptions(base_url=MOCK_URL), # calls /v1beta/models/{model}:generateContent
)
resp = client.models.generate_content(model="gemini-2.5-flash", contents="hello")
print(resp.text)import { createOpenAI } from "@ai-sdk/openai";
import { generateText } from "ai";
const dotmock = createOpenAI({ baseURL: `${process.env.MOCK_URL}/v1`, apiKey: "dotmock" });
const { text } = await generateText({
model: dotmock.chat("gpt-4o-mini"), // dotmock("gpt-4o-mini") uses the Responses API
prompt: "hello",
});from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini", base_url=f"{MOCK_URL}/v1", api_key="dotmock")
print(llm.invoke("hello").content)
# TypeScript
# new ChatOpenAI({ model: "gpt-4o-mini", apiKey: "dotmock",
# configuration: { baseURL: `${process.env.MOCK_URL}/v1` } })from llama_index.llms.openai_like import OpenAILike
llm = OpenAILike(
model="gpt-4o-mini",
api_base=f"{MOCK_URL}/v1",
api_key="dotmock",
is_chat_model=True,
is_function_calling_model=True,
)
print(llm.complete("hello"))Add the first fixture
Open Fixtures and create a fixture that matches the user message and returns content. Fixtures are evaluated in ascending priority and the first match wins, so give specific fixtures low numbers and keep an empty-match fallback last. The same fixture answers every provider route; DotMock renders it into each provider's response format.
The JSON below is the shape stored by the workspace, accepted by POST /mock-apis/$API_ID/llm-fixtures, and written under fixtures: in dotmock.yaml.
{
"name": "greeting",
"priority": 10,
"enabled": true,
"match": { "userMessage": "/\\b(hi|hello|hey)\\b/i" },
"response": {
"content": "Hello from DotMock. Order {{uuid}} is ready.",
"finishReason": "stop",
"usage": { "promptTokens": 12, "completionTokens": 9 }
}
}Expected result: Re-run the curl or SDK call: the assistant content starts with "Hello from DotMock", finish_reason is stop, and the request journal records the greeting fixture as the match.
Run the same fixtures offline
For local development and CI you can skip the hosted workspace entirely. dotmock init --llm writes a starter dotmock.yaml with greeting, tool-call, structured-output, refusal, rate-limit, and fallback fixtures; dotmock serve runs a local dotmock-server binary, or the ghcr.io/mockitohq/dotmock-server Docker image, with no account and no Redis.
npx @dotmock/cli init --llm # writes dotmock.yaml
npx @dotmock/cli serve # http://127.0.0.1:8080, hot-reloads on save
export OPENAI_BASE_URL=http://127.0.0.1:8080/assistant/v1
export ANTHROPIC_BASE_URL=http://127.0.0.1:8080/assistant
dotmock llm connect assistant --local # prints snippets for every SDK