API Endpoints
Call Monoize with OpenAI, Anthropic, embeddings, and image clients.
Base URL and authentication
Send requests to the Monoize listen address. The default is http://localhost:8080. Authenticate with an API key in one of these headers:
Authorization: Bearer sk-...
# or
x-api-key: sk-...Every endpoint below also exists under the /api prefix, for example /api/v1/chat/completions. Use the alias when a client hardcodes /api paths.
Any endpoint can reach any upstream type. For example, a client can call /v1/messages while the route serves the model through a chat_completion Channel. Monoize converts the protocol in both directions. Decision Channels are the exception: see Decisions.
Monoize preserves OpenRouter configuration_update messages on Chat routes, including updates with empty content. File data URIs retain their MIME type during conversion to Messages documents. Messages streams retain citations_delta citations. Responses content-filter termination remains an incomplete response rather than a length limit.
Chat and Responses convert supported URL citations to the target format. Unsupported citation locations stay within their source protocol. Token logprobs remain attached to matching text. Text changes discard scores that no longer match. Responses failure snapshots retain partial output, usage, and error details. Chat and Messages report failed or cancelled outcomes as errors. Messages preserve pause, compaction, and context-limit stop reasons. Billing includes every reported compaction iteration without counting the primary generation twice.
Raw reasoning, readable summaries, and opaque replay payloads remain separate during protocol conversion. Deleting raw reasoning does not restore it from a summary. Messages thinking text maps to a summary; its signature remains opaque. Invalid stream lifecycles and malformed known events produce errors. Complete Messages requests and responses reject truncated tool JSON; a native max_tokens stream may retain its incomplete argument bytes.
Chat reasoning fragments with the same stable identity accumulate once. A final snapshot adds only the unsent text suffix. Independent details remain separate.
Tool arguments can stream before completion. Tool signature envelopes wait for the completed tool value and preserve the signature as one opaque value.
Messages requests convert custom tools with an object input_schema, their JSON-object calls, and correlated results together. The conversion preserves call_id. Invalid schemas or arguments produce an error.
Responses objects with a non-null error and missing or invalid status produce an error. Empty objects are rejected. Error-free responses with an output array can omit status.
List models
curl http://localhost:8080/v1/models \
-H "Authorization: Bearer sk-..."The response lists the logical models available to the calling key, in the OpenAI list format.
Chat Completions
curl http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "my-model",
"messages": [{ "role": "user", "content": "Hello" }],
"stream": true
}'Set "stream": true for server-sent events. Omit it or set false for one JSON response.
Responses
curl http://localhost:8080/v1/responses \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "my-model",
"input": "Hello",
"stream": true
}'Notes:
- Send the returned Monoize id as
previous_response_idto continue a response through any upstream protocol. History is isolated by API key. - HTTP history defaults to
store=true. It lasts up to 30 minutes in this process. Restart or cache eviction removes it. - Set
store=falseto disable HTTP history retention. Unknown or expired ids return400 previous_response_not_found. Resend complete history after this error. - Supply current instructions and request controls on each call. Previous top-level
instructionsare not inherited. GET /v1/responsessupports Codex WebSocket v1 and v2. V1 emitsresponse.done; v2 emitsresponse.completed. Connection-local continuation also works withstore=false.GET /v1/codex/responsesuses the same WebSocket handler.POST /v1/codex/responsesuses the same HTTP handler. Both paths also have/apialiases.- A Responses WebSocket client may open an upstream WebSocket to a Responses Channel.
POST /v1/responsesstill uses HTTP. Handshake failure falls back to HTTP SSE on the same attempt. POST /v1/responses/compactcompacts a conversation.- Monoize forwards the native compact body to upstream
POST /v1/responses/compact. - After Channel selection, if that Channel maps
{model}-openai-compact, Monoize sends that sibling as the wire model. Otherwise it sends the conversation model. - Billing uses the conversation model price. The sibling ID does not need its own price row.
For Responses upstreams, Monoize preserves explicit include and reasoning.summary values. It does not add reasoning.encrypted_content or a default summary setting.
Disable reasoning
Set "reasoning_effort": "none" in Chat Completions requests. Set "reasoning": { "effort": "none" } in Responses requests.
Monoize preserves explicit none for OpenAI-compatible upstreams. A preserved native Chat reasoning object receives effort: "none" instead of the top-level shorthand.
Without explicit Messages controls, Monoize converts none to thinking: { "type": "disabled" } for Messages upstreams. Gemini upstreams receive generationConfig.thinkingConfig.thinkingBudget: 0.
DeepSeek Chat requests pass reasoning effort values through without remapping or generated thinking controls.
Omitting effort permits the upstream default. Use a model that supports disabled reasoning. Models with mandatory reasoning cannot honor this request.
Anthropic Messages
curl http://localhost:8080/v1/messages \
-H "x-api-key: sk-..." \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "my-model",
"max_tokens": 1024,
"messages": [{ "role": "user", "content": "Hello" }]
}'Gemini upstreams
Set the Channel upstream type to gemini to use Gemini through the existing endpoints. This support adds no public Gemini HTTP endpoint or Live API.
Monoize converts generateContent requests, responses, and conversation history in both directions. Streaming uses streamGenerateContent SSE.
- Text, reasoning, function calls, function results, and supported media retain their order and identity. Thought signatures remain attached to their original Parts.
- Generation controls, structured response formats, tools, and tool choice convert to their supported equivalents.
- Token logprobs remain attached to matching text. Changed text discards stale scores. Gemini permits at most 20 requested top logprobs.
- Representable citations and grounding links convert to the target format. Citation ranges retain their text locations, including non-ASCII text.
- Text and reasoning stream before completion. Atomic media and signed Parts can wait until complete. Failed or truncated streams produce errors.
- Monoize returns candidate index zero when present, otherwise the first candidate. It does not combine independent candidates.
Gemini-only tools, provider-executed code, and unsupported metadata stay within Gemini. A target protocol receives only the features it can represent.
Embeddings
curl http://localhost:8080/v1/embeddings \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "my-embedding-model",
"input": "The quick brown fox"
}'Decisions
Decision models answer typed questions with probabilities instead of text. Monoize accepts two request formats:
| Endpoint | Request format |
|---|---|
POST /v1/systemone | System One: state and a questions object with noul, choice, and score questions |
POST /v1/decisions | OpenAI Decisions: input and a questions array with predicate, choice, and score questions |
curl http://localhost:8080/v1/systemone \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "my-decision-model",
"state": "My payouts have failed for 3 days.",
"questions": {
"urgent": { "type": "noul", "instructions": "Is this request urgent?" },
"team": {
"type": "choice",
"instructions": "Which team owns this request?",
"criteria": { "billing": "Payments and refunds", "technical": "Bugs and outages" }
}
}
}'These endpoints route only to system_one and openai_decisions Channels. Other endpoints never route to these Channel types. Each decision endpoint can use both Channel types. Decision endpoints do not stream.
When the request format and the Channel format are the same, Monoize forwards every field and replaces only model. When they differ, Monoize converts the request and the answers:
- Text input converts in both directions. An object or array
statebecomes JSON text ininput. - Image parts require an
openai_decisionsChannel. If no such Channel serves the model, Monoize returns400 unsupported_decision_input. noulcriteria are appended to thepredicateinstructions. Boolean choice values become the System One keys"true"and"false".- An OpenAI
refusalanswer becomes{ "type": "refusal" }in a System One response. - Fields that the target format does not define are dropped, for example
safety_identifier.
Billing uses usage.input_tokens and usage.output_tokens from the upstream. Decision upstreams do not charge for output tokens, but some report them. Set the output price of each decision model to 0.
Images
Generation:
curl http://localhost:8080/v1/images/generations \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "my-image-model",
"prompt": "A lighthouse at dawn",
"size": "1024x1024"
}'Upload image files with multipart/form-data:
curl http://localhost:8080/v1/images/edits \
-H "Authorization: Bearer sk-..." \
-F model="my-image-model" \
-F prompt="Add a red boat" \
-F 'image[]=@input.png'Add -F mask=@mask.png to apply a PNG mask. Edits accept 1–16 source images and at most one mask.
Use JSON for image references:
curl http://localhost:8080/v1/images/edits \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "my-image-model",
"prompt": "Add a red boat",
"images": [{ "image_url": "https://example.com/input.png" }],
"mask": { "image_url": "https://example.com/mask.png" }
}'Each images entry and optional mask object accepts exactly one image_url or file_id. An image_url accepts an HTTP(S) URL or a Base64 data URL. File IDs must be accessible with the selected upstream credentials. A file ID does not transfer a file between upstream accounts or Providers.
Both endpoints require model and prompt. Non-streaming n requests still run as independent sub-requests. Set stream=true with n=1 for image SSE events. Native openai_image routes send inline images as multipart. If any input or mask retains an HTTP(S) URL or file reference, those routes send JSON.
With stream=true, Monoize sends an immediate SSE heartbeat and another after 15 seconds without a data event. OpenRouter image edits use non-streaming upstream requests automatically. Other routes retry once without streaming after an explicit HTTP 400 or 422 streaming rejection. JSON image responses become completed events without synthetic previews. Billing and logs remain one streaming request. Ordinary network errors do not trigger this transport fallback. This keeps downstream connections active during generation; it does not extend the upstream request timeout.
For Responses routes, configure image_enable_openai_generation_tool. Image settings override transform defaults, and masks become the tool's input_image_mask. Image background configures the tool; it is separate from the Responses boolean background. Responses routes reject image style and response_format="url" with an explicit error.
Image responses preserve upstream-reported quality, size, background, output_format, and image model. Missing values remain absent; request values are not proof of upstream execution. An explicit upstream mime_type or media_type sets output_format when output_format is absent. Each returned image includes mime_type. For multiple images, a top-level field appears only when every image reports the same value. Completed image stream events report metadata for their own image.
Use official SDKs
Point an official SDK at Monoize by setting its base URL:
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8080/v1",
api_key="sk-...",
)import anthropic
client = anthropic.Anthropic(
base_url="http://localhost:8080",
api_key="sk-...",
)Error responses
| HTTP status | Code | Meaning |
|---|---|---|
401 | unauthorized | The API key is missing, invalid, disabled, or expired |
402 | insufficient_balance | The user or sub-account balance is empty |
403 | model_not_allowed | The key's model limits reject the requested model |
403 | ip_not_allowed | The client IP is not in the key's IP whitelist |
502 | upstream_error | No route serves the model, or all eligible routes failed |
Upstream error text is sanitized before it reaches the client. Read the full detail in Request Logs.