Monoize

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_id to 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=false to disable HTTP history retention. Unknown or expired ids return 400 previous_response_not_found. Resend complete history after this error.
  • Supply current instructions and request controls on each call. Previous top-level instructions are not inherited.
  • GET /v1/responses supports Codex WebSocket v1 and v2. V1 emits response.done; v2 emits response.completed. Connection-local continuation also works with store=false.
  • GET /v1/codex/responses uses the same WebSocket handler. POST /v1/codex/responses uses the same HTTP handler. Both paths also have /api aliases.
  • A Responses WebSocket client may open an upstream WebSocket to a Responses Channel. POST /v1/responses still uses HTTP. Handshake failure falls back to HTTP SSE on the same attempt.
  • POST /v1/responses/compact compacts 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:

EndpointRequest format
POST /v1/systemoneSystem One: state and a questions object with noul, choice, and score questions
POST /v1/decisionsOpenAI 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 state becomes JSON text in input.
  • Image parts require an openai_decisions Channel. If no such Channel serves the model, Monoize returns 400 unsupported_decision_input.
  • noul criteria are appended to the predicate instructions. Boolean choice values become the System One keys "true" and "false".
  • An OpenAI refusal answer 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 statusCodeMeaning
401unauthorizedThe API key is missing, invalid, disabled, or expired
402insufficient_balanceThe user or sub-account balance is empty
403model_not_allowedThe key's model limits reject the requested model
403ip_not_allowedThe client IP is not in the key's IP whitelist
502upstream_errorNo 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.

On this page