Open source · MIT · Self-hosted AI gateway

Speak, friend, and enter.

One guarded gateway for every AI provider. Add credentials once, point every OpenAI-compatible tool at a single local endpoint.

Open the live demo
npm install -g durindoor
Star bloodf/durindoor on GitHub

One door, every provider

Not just chat. Every kind of model call.

The same key and base URL reach chat, embeddings, speech, images, video and the web. Whatever the modality, it walks through the same door.

237providers in the registryOAuth logins, API keys, web cookies, free tiers and local runtimes
  • 195 providers

    Chat & code

    /v1/chat/completions
  • 14 providers

    Embeddings

    /v1/embeddings
  • 13 providers

    Text to speech

    /v1/audio/speech
  • 6 providers

    Speech to text

    /v1/audio/transcriptions
  • 20 providers

    Image generation

    /v1/images/generations
  • 12 providers

    Vision

    image input
  • 4 providers

    Video

    /v1/video/generations
  • 16 providers

    Web search

    /v1/search
  • 6 providers

    Web fetch

    /v1/web/fetch

Provider counts come from the DurinDoor provider registry. Support for each modality depends on the provider.

How it works

Every request passes one door

Your tools speak OpenAI. Your providers speak whatever they like. DurinDoor stands between them, holds the keys, and keeps the ledger.

Requests from Claude Code, Codex, Cursor and Cline pass through DurinDoor on localhost:20128 and are routed to OpenAI, Anthropic, Gemini, OpenRouter, DeepSeek or Ollama.DurinDoorlocalhost:20128/v1Claude CodeCodexCursorClineOpenAIAnthropicGeminiOpenRouterDeepSeekOllamaRequests from Claude Code, Codex, Cursor and Cline pass through DurinDoor on localhost:20128 and are routed to OpenAI, Anthropic, Gemini, OpenRouter, DeepSeek or Ollama.DurinDoorlocalhost:20128/v1Client: Claude CodeClient: CodexClient: CursorClient: ClineProvider: OpenAIProvider: AnthropicProvider: GeminiProvider: OpenRouterProvider: DeepSeekProvider: Ollama
  1. 01

    Knock

    A tool sends a /v1 request with a DurinDoor key and a model string.

  2. 02

    Resolve

    The key is checked, the model resolved, and a healthy connection chosen.

  3. 03

    Translate

    Formats are bridged both ways; the upstream call uses stored credentials.

  4. 04

    Record

    Usage, latency and outcome land in local SQLite as the response streams back.

model resolution

"model": "

  • resolve provider model
  • provider openai
  • upstream gpt-4.1
  • 200 OK stream · 412 ms

Three tiers of fallback

When one door is shut, try the next.

Put a subscription first, a cheap API second and a free or local model last. A combo keeps one stable model name; when a member fails, DurinDoor retries other accounts for it, then falls through to the next member.

try 1 cc/claude-sonnet

Sticky round-robin rotate after 3 uses, or pin a session to one account

  • Account A
  • Account B
  • Account C
  1. Tier Itrying

    Subscription

    The plan you already pay for, such as Claude Code or Codex, connected through OAuth.

    cc/claude-sonnet
  2. Tier IIstanding by

    Cheap API

    Low-cost API keys and compatible endpoints take over when the subscription is rate limited.

    openrouter/qwen3-coder
  3. Tier IIIstanding by

    Free & local

    Free tiers or a local model keep the request alive when everything upstream says no.

    ollama-local/qwen3

The fellowship

Every provider, bound to one ring

Connect OAuth subscriptions, API keys, web cookies, OpenAI- or Anthropic-compatible endpoints and local runtimes. Tools never learn which one answered.

Registry
237 providers
Custom nodes
Any compatible URL
Local
No remote account
DurinDoor

Compatible tools

If it speaks OpenAI, it walks through

Coding agents, editors and CLIs connect with one base URL and one DurinDoor key.

  • Claude Code
  • OpenAI Codex
  • Cursor
  • Cline
  • Kilo Code
  • Droid
  • OpenCode
  • GitHub Copilot
  • Hermes
  • Continue
  • Roo Code
  • Gemini CLI
  • Antigravity
  • Kiro
  • Amp
  • OpenClaw

Token savers

Say less. Mean the same.

Opt-in compression trims prompts after translation and before they leave your machine. It fails open: if an engine errors, the original request goes through untouched.

−1,815bytes removed from this tool result
82%smaller: grouped by folder, long lists capped
find . -type f2,203 bytes
./open-sse/providers/registry/9router.js
./open-sse/providers/registry/agentrouter.js
./open-sse/providers/registry/aihorde.js
./open-sse/providers/registry/alibaba.js
./open-sse/providers/registry/anthropic.js
./open-sse/providers/registry/antigravity.js
./open-sse/providers/registry/assemblyai.js
./open-sse/providers/registry/azure.js
./open-sse/providers/registry/baidu.js
./open-sse/providers/registry/bedrock.js
./open-sse/providers/registry/black-forest-labs.js
./open-sse/providers/registry/brave-search.js
./open-sse/providers/registry/cartesia.js
./open-sse/providers/registry/cerebras.js
./open-sse/providers/registry/claude.js
./open-sse/providers/registry/cline.js
./open-sse/providers/registry/codex.js
./open-sse/providers/registry/cohere.js
./open-sse/providers/registry/copilot-web.js
./open-sse/providers/registry/cursor.js
./open-sse/providers/registry/deepgram.js
./open-sse/providers/registry/deepseek.js
./open-sse/providers/registry/elevenlabs.js
./open-sse/providers/registry/exa.js
./open-sse/providers/registry/firecrawl.js
./open-sse/providers/registry/fireworks.js
./open-sse/providers/registry/gemini.js
./open-sse/providers/registry/github.js
./open-sse/providers/registry/glm.js
./open-sse/providers/registry/groq.js
./open-sse/providers/registry/huggingface.js
./open-sse/providers/registry/kimi.js
./open-sse/providers/registry/kiro.js
./open-sse/providers/registry/minimax.js
./open-sse/providers/registry/mistral.js
./open-sse/providers/registry/nvidia.js
./open-sse/providers/registry/ollama.js
./open-sse/providers/registry/ollama-local.js
./open-sse/providers/registry/openai.js
./open-sse/providers/registry/openrouter.js
./open-sse/providers/registry/perplexity.js
./open-sse/providers/registry/qwen.js
./open-sse/providers/registry/together.js
./open-sse/providers/registry/vertex.js
./open-sse/providers/registry/xai.js
./open-sse/translator/index.js
./open-sse/translator/validate.js
./open-sse/translator/webTools.js
./open-sse/translator/formats.js
./open-sse/translator/formats/claude.js
./open-sse/translator/formats/gemini.js
./open-sse/translator/formats/responsesApi.js
./open-sse/translator/formats/openai.js
./open-sse/translator/formats/maxTokens.js
RTK
after RTK find filter388 bytes
54 files in 3 dirs:

./open-sse/providers/registry/  (45)
  9router.js
  agentrouter.js
  aihorde.js
  alibaba.js
  anthropic.js
  antigravity.js
  assemblyai.js
  azure.js
  baidu.js
  bedrock.js
  +35
./open-sse/translator/  (4)
  index.js
  validate.js
  webTools.js
  formats.js
./open-sse/translator/formats/  (5)
  claude.js
  gemini.js
  responsesApi.js
  openai.js
  maxTokens.js

Real output of DurinDoor's RTK find filter, using the sample file list.

  • RTK filters

    Condense tool output such as git status, git diff, ls, grep, find and build logs.

  • Caveman

    Rule-based prose compression with lite, full and ultra intensities.

  • Session dedup

    Drops blocks repeated across turns of the same conversation.

  • Headroom

    Optional adapter that only applies when it saves more than five percent.

Need the raw prompt for one call?X-DurinDoor-Token-Saver: off

The ledger

Know which account still has room

DurinDoor records every call in local SQLite and tracks provider limits and reset windows, so you can see which account still has headroom before a tool hits a wall.

Sample data
  • 82%used

    Claude Code

    subscription · resets in 1h 12m

  • 46%used

    Codex

    subscription · resets in 3d

  • 27%used

    Gemini

    free tier · resets daily

In the dashboard

  • Provider, model, tokens, cost estimate and latency for every request
  • Which model served each request, and the fallback outcome
  • Provider limits and reset windows side by side

What the door guards

Everything between your tools and your providers

Credentials, routing, fallbacks, translation and the ledger of every call, all on hardware you control.

  • 01

    Combos

    Stack models behind one stable name. A failed member falls through to the next, so tools never change their config.

  • 02

    Format translator

    Send OpenAI-shaped requests; Claude, Gemini, Kiro, Cursor, Ollama and Vertex formats are handled upstream.

  • 03

    Multi-account

    Several connections per provider. Locked or expired accounts are skipped and OAuth tokens refresh.

  • 04

    Tunnels

    Reach your gateway from another network over HTTPS. Keep dashboard auth on, turn it off when unused.

  • 05

    Proxy pools

    Route upstream traffic through configured proxies for regional routing or egress control.

  • 06

    MITM bridge

    Optional local interception for supported IDE traffic, behind explicit setup and trust changes.

  • 07

    MCP gateway

    Expose multiple MCP servers behind managed keys and routes from the same dashboard.

  • 08

    One dashboard

    Providers, API keys, combos, usage, request logs, endpoint setup, CLI tools, tunnels, MITM and MCP in one browser UI.

  • 09

    CLI tool setup

    Copy ready integration settings for Claude Code, Codex, Cursor, Cline and more.

  • 10

    Self-hosted state

    Storage, credentials and logs live in your DATA_DIR. You decide who can reach it.

Before and after

Wiring every tool by hand, or one door

What changes when your tools stop talking to providers directly.

Per-tool provider setup compared with DurinDoor
When you needPer-tool setupDurinDoor
Base URL your tools point atA different one per providerOne: localhost:20128/v1
Where provider credentials liveCopied into every tool's configYour DATA_DIR, added once
A provider returns 429The request failsNext account, then next combo member
Claude, Gemini or Kiro formatsA separate SDK or adapter eachTranslated from OpenAI shape
Tokens, cost and latencyScattered across provider consolesOne request log and usage view
Plan limits and reset windowsChecked by handQuota tracker in the dashboard
Several MCP serversWired into each clientOne MCP gateway with managed keys
Source and hostingDepends on the vendorMIT, runs on hardware you choose

Quick start

Three steps to the other side

Install, start, and point any OpenAI-compatible client at one base URL.

  1. Install the CLI

    Node.js 20.20.2 and npm 10.8.2. One global package, no accounts.

    shell
    $ npm install -g durindoor
  2. Open the door

    First run creates DATA_DIR and the database, then serves the dashboard.

    shell
    $ durindoor
     dashboard  http://localhost:20128/dashboard
     api base   http://localhost:20128/v1
  3. Send a request

    Add a provider, create a key, and use any model, alias or combo name.

    curl
    curl http://localhost:20128/v1/chat/completions \
      -H "Authorization: Bearer YOUR_DURINDOOR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "MODEL_ID",
        "messages": [
          {"role": "user", "content": "Reply with one short sentence."}
        ],
        "max_tokens": 32
      }'
    

Connect your tools

Base URL
http://localhost:20128/v1
API key
your DurinDoor API key
Model
model ID, alias, or combo

Other ways through

Requires Node.js 20.20.2 and npm 10.8.2. Serves on port 20128.
$ npm install -g durindoor
$ durindoor

Live demo

Walk through the dashboard, no install

The demo runs the real DurinDoor interface against mocked data, so you can click every page before you run it yourself.

localhost:20128/dashboard/usage
Open the live demo
Demo passwordmelon

Mocked data. Nothing leaves your browser.

Pedo mellon a minno

Speak, friend, and enter.

Install it on your machine in a minute, or walk through the live demo first. The word is on the door.

View source