DurinDoor
Getting started

First request

Choose a model and send OpenAI Chat Completions, Responses, or Anthropic Messages with a DurinDoor key.

Start with a running gateway, a connected provider, and a DurinDoor API key. In the dashboard, open API Keys, create a key, and copy its secret. This is the gateway key, not the provider's API key.

Choose the request format your client uses. DurinDoor translates it to the selected provider's supported format.

FormatEndpoint
OpenAI Chat CompletionsPOST /v1/chat/completions
OpenAI ResponsesPOST /v1/responses
Anthropic MessagesPOST /v1/messages

All examples below need a model ID available on your instance. Run this first, then replace PROVIDER/MODEL in the examples:

curl http://localhost:20128/v1/models \
  -H "Authorization: Bearer YOUR_DURINDOOR_API_KEY"

This catalog call chooses an exposed model. On loopback it does not validate the gateway key. The POST below verifies provider inference. It verifies key validity when Require API Key is enabled; loopback requests with enforcement off can admit unknown keys.

Model names

The model field is a string. A slash splits it into provider (or alias) and upstream id:

provider/model

openai/gpt-4.1 is provider openai plus model gpt-4.1. Registry aliases in the first segment resolve to a provider id. Use an explicit provider prefix when you want a particular account family. A bare name can resolve to a saved alias or combo; otherwise the gateway infers a provider from the model name.

Other accepted values: a compatible-node id (openai-compatible-lab/model-name), a custom alias you defined, or a combo name from the Combos page. GET /v1/models lists what this instance currently exposes.

Choose a request format

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

For OpenAI Chat, expect assistant text under choices[0].message.content. Anthropic replies put text blocks under content; Responses uses output. Check Usage to confirm the selected provider.

The body must be JSON with Content-Type: application/json. A missing or rejected key returns 401. A body that is not parseable returns 400. For OpenAI Chat, omit stream or set it to false for a single JSON response.

Node.js

Install the SDK before running this example in an ES module:

npm install openai
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: "YOUR_DURINDOOR_API_KEY",
  baseURL: "http://localhost:20128/v1",
});

const response = await client.chat.completions.create({
  model: "PROVIDER/MODEL",
  messages: [{ role: "user", content: "Say hello." }],
});

console.log(response.choices[0].message.content);

Python

Install the SDK before running this example:

python -m pip install openai
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_DURINDOOR_API_KEY",
    base_url="http://localhost:20128/v1",
)

response = client.chat.completions.create(
    model="PROVIDER/MODEL",
    messages=[{"role": "user", "content": "Say hello."}],
)

print(response.choices[0].message.content)

Streaming

Set "stream": true in the body. OpenAI clients stream only when that flag is exactly true. Some providers always stream upstream; the gateway then accumulates the provider stream and can still return a JSON body to a client that asked for it.

curl http://localhost:20128/v1/chat/completions \
  -H "Authorization: Bearer YOUR_DURINDOOR_API_KEY" \
  -H "Content-Type: application/json" \
  -N \
  -d '{
    "model": "PROVIDER/MODEL",
    "stream": true,
    "messages": [
      {"role": "user", "content": "Count to three."}
    ]
  }'

Use curl -N to see chunks as they arrive. A stream can fail after HTTP 200; inspect error events and confirm that the stream reaches its completion marker.

Errors

Non-streaming failures look like:

{
  "error": {
    "message": "Invalid API key provided",
    "type": "authentication_error",
    "code": "invalid_api_key"
  }
}

Gateway-generated errors normally include message, type, and code. Upstream or provider-specific errors can include additional fields. Status 400 is invalid_request_error / bad_request. 401 is authentication_error / invalid_api_key. 404 is invalid_request_error / model_not_found. 429 is rate_limit_error / rate_limit_exceeded. 5xx uses server_error with codes such as bad_gateway. A 415 from a wrong Content-Type uses invalid_request_error / unsupported_media_type. For 401, copy the DurinDoor key again. For 404, use an ID from your instance. For 429, inspect Quota Tracker and any Retry-After header. For 5xx, inspect request details and provider health.

On this page

Edit on GitHub