OpenAI-compatible proxy API. Everything below is a drop-in for the OpenAI Chat Completions API.
The marketing pages you're reading and the API share this domain — the browser gets HTML at /, your client hits the API path below.
The npx mrvinciapi wizard asks for your key, lets you pick your client, writes the config, and verifies the connection. Zero dependencies, pure Node — it only edits local files, never sends anything anywhere.
npx mrvinciapi --openai
# Claude Code npx mrvinciapi sk_mv_YOUR_KEY # Codex (OpenAI Responses) npx mrvinciapi sk_mv_YOUR_KEY --codex # Cursor / Cline npx mrvinciapi sk_mv_YOUR_KEY --openai
# print env, change nothing npx mrvinciapi sk_mv_YOUR_KEY --print # revert Claude Code npx mrvinciapi --undo
Override hosts with MRVINCI_CLAUDE_BASE / MRVINCI_OPENAI_BASE for a self-hosted gateway.
Codex defaults to wire_api = "responses". We serve a full OpenAI Responses endpoint at /v1/responses (streaming + non-streaming), so Codex works out of the box — npx mrvinciapi <key> --codex writes this for you.
Or add it to ~/.codex/config.toml and run codex --profile mrvinci:
[model_providers.mrvinci] name = "MrVinci" base_url = "https://openai.mrvinci.app/v1" wire_api = "responses" env_key = "MRVINCI_API_KEY" [profiles.mrvinci] model = "gpt-5.4" model_provider = "mrvinci"
Export the key first: export MRVINCI_API_KEY="sk_mv_…".
Add to ~/.claude/settings.json:
{
"env": {
"OPENAI_API_KEY": "sk_mv_YOUR_KEY",
"OPENAI_BASE_URL": "https://openai.mrvinci.app"
}
}
Base URL https://openai.mrvinci.app, API key sk_mv_…, model DeepSeek-V4-Pro.
curl https://openai.mrvinci.app/v1/chat/completions \
-H "Authorization: Bearer sk_mv_YOUR_KEY" \
-H "content-type: application/json" \
-d '{
"model": "DeepSeek-V4-Pro",
"messages": [{"role":"user","content":"Hello"}]
}'
Authenticate with x-api-key: sk_mv_… or Authorization: Bearer sk_mv_…. List models at /v1/models.
Send the OpenAI-compatible model, prompt, size, quality, and n fields. Image calls are billed per image, not per token.
curl https://openai.mrvinci.app/v1/images/generations \
-H "Authorization: Bearer sk_mv_YOUR_KEY" \
-H "content-type: application/json" \
-d '{
"model": "gpt-image-1-5",
"prompt": "A brass astrolabe on a drafting table",
"size": "1024x1024",
"quality": "medium",
"n": 1
}'
Models: gpt-image-1-5, flux-2-pro. size and quality select the GPT Image price tier; FLUX is flat-rate. This generation endpoint does not accept reference images.
Everything the Chat Completions / Responses API supports works through the gateway — these aren't add-ons, they're the same wire format you already use.
Send a tools array exactly as the OpenAI SDK does — tool_use blocks stream back exactly as the API specifies. Agents like Claude Code, Cursor, and Cline run their whole tool loop through the gateway unmodified.
curl https://openai.mrvinci.app/v1/chat/completions \
-H "Authorization: Bearer sk_mv_YOUR_KEY" \
-H "content-type: application/json" \
-d '{
"model": "DeepSeek-V4-Pro",
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}
}
}],
"messages": [{"role":"user","content":"Weather in Florence?"}]
}'
Set "stream": true for server-sent events with no added buffering — text deltas, tool calls arrive as they're generated.
Send images as image_url parts — exactly as the API specifies, streaming included.
POST /v1/images/generations returns generated images in the OpenAI-compatible response shape and bills each image at its model tier.
Cache reads are metered separately (cache_read_input_tokens in every response's usage) and billed at a fraction of the input price — keep your system prompt stable and long agent sessions get dramatically cheaper. No opt-in needed.
POST /v1/responses serves the full OpenAI Responses wire format (streaming + non-streaming) — Codex and the Agents SDK work with zero config beyond the base URL.
Errors come back in the OpenAI error envelope, so SDK retry logic behaves correctly. The rule: 429 and 529 are retryable (wait, then retry); 4xx everything else means fix the request.
| Status | Meaning | What to do |
|---|---|---|
| 401 | Key missing, invalid, expired, or revoked — the message says which. | Check the key on /usage; ask an admin to renew. |
| 404 | Unknown model id. | Pick an id from /v1/models. |
| 413 | Request body over 32 MB (a very long unmanaged conversation). | Don't retry the same body — compact or clear the conversation. |
| 429 | Prepaid credit exhausted or per-minute limit reached. | Honor retry-after or top the key up. |
| 529 | The service is temporarily overloaded. | Retry with backoff — official SDKs do this automatically. |
Restart your IDE after editing its settings so it re-reads the base URL.
The status page live-checks every endpoint from your browser. If it's green and you're still stuck, it's the key or the request.
Paste it on the usage page — revoked/expired state, limits, and per-model consumption are all visible, read-only.
Proxies and some serverless runtimes buffer SSE. Test with curl -N first; if that streams, the issue is between your app and us.