DurinDoor
Reference

Provider plugin manifest

JSON provider metadata at GET /v1/provider-plugin-manifest, sidecar eligibility, and the CLIProxyAPI header.

GET /v1/provider-plugin-manifest returns provider metadata for sidecars such as CLIProxyAPI. /api/v1/provider-plugin-manifest is the same endpoint. No authentication is required.

OPTIONS is allowed. The JSON response is Cache-Control: public, max-age=60 with Access-Control-Allow-Origin: *.

The JSON excludes registry functions, OAuth client secrets, and session-pool objects. Static upstream headers are included.

GET http://localhost:20128/v1/provider-plugin-manifest

Document shape

Top-level object:

FieldValue
schemaVersion1
generatedFrom"open-sse/providers/registry"
providersArray of entries, sorted by id

A client that fetches this URL rejects the body when schemaVersion is not 1 or providers is not an array.

Each provider entry:

FieldSource
idRegistry id
aliasPresent when the registry sets alias
aliasesPresent when the registry has a non-empty aliases array
formattransport.format, or "openai"
executortransport.executor, then executor, then "default"
authCompact object: type, header, prefix (see below)
endpointsCompact object of static URL fields
capabilitiesSorted tag list
passthroughModelstrue when the registry sets that flag
defaultContextLengthPresent when the registry value is a number
timeoutMsPresent when transport.timeoutMs is a number
modelsMapped model rows
sidecar{ eligible, reasons }

endpoints may include baseUrl, baseUrls, responsesBaseUrl (from responsesBaseUrl or responsesUrl), chatPath, modelsUrl, headers (a shallow copy of transport.headers), and urlSuffix. Missing values are omitted.

Each model row may include id, name, contextLength, maxOutputTokens, toolCalling, supportsReasoning, supportsVision, unsupportedParams, targetFormat, and kind. Undefined fields are omitted.

Auth object

auth.type is not the registry category. It is derived in this order:

  1. entry.authType when set
  2. "none" when noAuth === true
  3. "oauth" when hasOAuth, oauth, or authModes includes "oauth"
  4. "apikey" otherwise

auth.header is transport.auth.header, then transport.auth.apiKey.header, then "x-api-key" for format === "claude", else "Authorization".

auth.prefix is "Bearer" when the scheme is "bearer". Otherwise it is transport.auth.prefix or transport.auth.apiKey.prefix.

Sidecar eligibility

sidecar.eligible is true only when reasons is empty. Treat it as a candidate signal. An ineligible provider remains available through DurinDoor's own executor.

A reason is recorded when any of these hold:

CheckReason text
executor is not "default"custom executor: <name>
auth.type is not apikey, optional, or noneauth type requires JS handling: <type>
no baseUrl, baseUrls, responsesBaseUrl, or responsesUrlno static upstream endpoint
any of those URLs contains {...}templated URL requires JS handling
transport.urlBuilder is a functiondynamic URL builder
oauth or hasOAuthoauth metadata
poolConfig is setsession pool config
format is gemini, gemini-tts, or gemini-sttGemini endpoint constructed at dispatch

capabilities is a sorted set. Tags that can appear: apikey, oauth, responses, passthrough-models, custom-executor, sidecar-candidate. sidecar-candidate is added only when sidecar.eligible is true.

Eligible does not mean the sidecar implements the provider. Custom executors, OAuth, templated URLs, Gemini formats, and session pools stay on the JavaScript path until the sidecar has equivalent behavior.

The loader does not emit OAuth client secrets, urlBuilder functions, or poolConfig internals. Static transport.headers do go out on endpoints.headers.

CLIProxyAPI header

When DurinDoor dispatches through the cliproxyapi executor, the outbound request includes X-OmniRoute-Provider-Manifest-Url. That value is resolved from trusted server configuration only. Inbound Origin is ignored.

The advertised URL uses this precedence:

  1. OMNIROUTE_PROVIDER_MANIFEST_URL if non-empty
  2. BASE_URL or NEXT_PUBLIC_BASE_URL when the value looks like http:// or https://, with /api/v1/provider-plugin-manifest appended
  3. Otherwise {OMNIROUTE_PUBLIC_PROTOCOL || http}://{HOST || 127.0.0.1}:{PORT || DASHBOARD_PORT || API_PORT || 20128}/api/v1/provider-plugin-manifest

Set OMNIROUTE_PROVIDER_MANIFEST_URL when the sidecar cannot reach the local DurinDoor origin. CLIProxyAPI itself is optional. Host and port defaults for the sidecar process are CLIPROXYAPI_HOST (127.0.0.1) and CLIPROXYAPI_PORT (8317).

On this page

Edit on GitHub