Skip to main content
POST
Create a model mapping

Authorizations

Authorization
string
header
required

A Barndoor API key, sent as Authorization: Bearer <key>. Keys are prefixed bdai_ and are opaque — do not attempt to decode one. Interchangeable with an OAuth 2.0 access token.

Body

application/json
model_alias
string
required
provider_id
string<uuid>
required
upstream_model
string
required
bare_alias
boolean | null

Whether a route target participates in bare-name resolution. Defaults to true for a route and is always false for an enablement, which is reachable only as <provider>/<model>.

change_note
string | null

Optional free-text note explaining why this route was added (BCP-3998). Surfaced on the row and mirrored into the audit event.

cooldown_429_default_secs
integer<int32> | null

Cooldown on an upstream 429 that carries no usable Retry-After (a Retry-After sets the window instead). Range 1-3600, and at most cooldown_max_secs; default 30.

cooldown_base_secs
integer<int32> | null

First cooldown window once the threshold trips, doubled on each failed recovery probe up to cooldown_max_secs. Range 1-3600, and at most cooldown_max_secs; default 30.

cooldown_failure_threshold
integer<int32> | null

Gateway failures (5xx, timeouts, connection errors, managed-key 401/403) within cooldown_window_secs that cool the route. 0 disables every cooldown of the shared route (rolling failures, 429 and 529); per-user credential cooldowns on passthrough routes still apply. Range 0-100; default 10.

cooldown_max_secs
integer<int32> | null

Cap on every cooldown window: doubling, 429 and 529. Range 1-86400; default 300.

cooldown_overloaded_secs
integer<int32> | null

Flat cooldown on an upstream 529 "overloaded" with no usable Retry-After; it does not spend the failure budget. 0 counts a 529 as an ordinary gateway failure instead. Range 0-3600, and at most cooldown_max_secs unless 0; default 10.

cooldown_window_secs
integer<int32> | null

Width of the rolling failure window, seconds. Range 1-3600; default 60.

enabled
boolean
kind
enum<string> | null

model enables the model on the provider; route adds a target to the route named model_alias, which may be the upstream's own name.

Omitted, it is inferred the way callers predating the field meant it (see [MappingKind::infer]): model_alias == upstream_model without bare_alias: true is an enablement, anything else a route. A route named after its upstream with no enablement yet on the provider is accepted only in that legacy form, which enables the model first.

Available options:
model,
route
priority
integer<int32>
request_timeout_secs
integer<int32> | null

Per-mapping total-request timeout for non-streaming responses (streaming responses have no total timeout). On a custom-alias row this sets the route tier; on a 1:1 enablement (anchor) row it sets the model tier consulted for every alias of that model. None (the default) lets model_mappings.create write the platform default (TOTAL_REQUEST_TIMEOUT_DEFAULT_SECS) at the route tier. The range is fixed platform policy (TOTAL_REQUEST_TIMEOUT_MIN_SECS..=TOTAL_REQUEST_TIMEOUT_MAX_SECS); see [crate::proxy::timeouts].

retry_on_429_count
integer<int32>

Same-route retries on upstream 429. 0 means immediate failover.

retry_on_429_max_wait_secs
integer<int32>

Cap on honoring upstream Retry-After. 0 means use a small default.

source
enum<string> | null

Where this model came from. The Add Models dialog sends Custom from its free-text branch and Catalog from the picker; those two paths already differ client-side, and this is what carries the difference through to storage.

None means "infer": the handler inherits the anchor's provenance when one exists (so a route created on Model Routes agrees with the enablement it points at), and otherwise falls back to Catalog. SDK and curl callers therefore land on Catalog by default — accepted, since the pill exists to catch a typo in the UI and an API caller is not its audience.

Available options:
catalog,
custom
stream_idle_timeout_secs
integer<int32> | null

Per-mapping stream-idle (per-chunk) timeout for streaming responses. None (the default) lets model_mappings.create write the platform default (STREAM_IDLE_TIMEOUT_DEFAULT_SECS) at the route tier. The range is fixed platform policy (STREAM_IDLE_TIMEOUT_MIN_SECS..=STREAM_IDLE_TIMEOUT_MAX_SECS); see [crate::proxy::timeouts].

Response

The created record

Who created and last changed this route, and why (BCP-3998).

Read with try_get, so the reads that don't select the columns come back unattributed rather than failing.

cooldown_429_default_secs
integer<int32>
required

Cooldown on a 429 with no usable Retry-After, seconds.

cooldown_base_secs
integer<int32>
required

First cooldown window, doubled on each failed recovery probe up to cooldown_max_secs.

cooldown_failure_threshold
integer<int32>
required

Gateway failures within cooldown_window_secs that cool the route. 0 disables every cooldown of the shared route.

cooldown_max_secs
integer<int32>
required

Cap on every cooldown window.

cooldown_overloaded_secs
integer<int32>
required

Flat cooldown on a 529 "overloaded" with no usable Retry-After, seconds. 0 counts a 529 as an ordinary gateway failure instead.

cooldown_window_secs
integer<int32>
required

Width of the rolling failure window, seconds.

bare_alias
boolean
required

When true the row participates in bare-name resolution (POST /v1/chat/completions {"model": "<alias>"}). Route targets are true; enablements (kind = model) are always false and are addressable solely via the explicit <provider>/<upstream> form.

enabled
boolean
required
id
string<uuid>
required
kind
enum<string>
required

Whether this row is the model's enablement or a route target — see [MappingKind]. Never inferred from model_alias == upstream_model: a route may carry its upstream's name (migration V84).

Available options:
model,
route
model_alias
string
required
priority
integer<int32>
required
provider_id
string<uuid>
required
retry_on_429_count
integer<int32>
required

Same-route retries on upstream 429. 0 means immediate failover.

retry_on_429_max_wait_secs
integer<int32>
required

Cap on honoring upstream Retry-After header. 0 means use a small built-in default and ignore the header value.

source
enum<string>
required

Whether the model was picked from the provider catalog or typed in by an admin. Stamped once at create time and never recomputed — see [ModelSource] and migration V61.

Available options:
catalog,
custom
upstream_model
string
required
created_by_email
string | null
created_by_name
string | null
created_by_user_id
string<uuid> | null
last_change_note
string | null

Optional free text explaining why the last change was made ("Raised for the Q3 batch job", "Vendor deprecated the old endpoint").

Admin-authored and rendered in the portal, so it is untrusted input: length-capped here, escaped on render.

last_modified_at
string<date-time> | null

When the change named by last_modified_by_* happened.

Its own column rather than the row's updated_at, because updated_at is bumped by writes nobody is attributed for -- pairing the two would date a named admin's edit to a background job's clock. See the V75 migration for the full reasoning.

last_modified_by_email
string | null
last_modified_by_name
string | null
last_modified_by_user_id
string<uuid> | null
auto_disabled_reason
enum<string> | null

Set when the gateway turned this row off (BCP-3811's full sync retiring a model the catalog dropped). None means a human decided the enabled flag, and the reconciler will not touch it in either direction — see migration V63. Any admin write to enabled clears this.

Clearing it is not a durable claim on the row, and it is easy to read it that way. It protects a human's disable — the re-enable branch requires the marker to be present, so a row a human turned off is never turned back on. It cannot protect a human's re-enable: a cleared marker is exactly what makes the row eligible for retirement again, so under full a model the catalog still does not list is re-disabled on the next tick. That is full's contract ("enabled set tracks the catalog"), not a bug — see model_sync::tests::re_enabling_a_dropped_model_is_retired_again_on_the_next_tick.

Available options:
catalog_retired
request_timeout_secs
integer<int32> | null

Per-mapping (route-tier / model-tier) total-request timeout for non-streaming requests (streaming responses have no total timeout). Defaults to TOTAL_REQUEST_TIMEOUT_DEFAULT_SECS at insert. On a route target this is the route tier; on the enablement (kind = model) it is the model tier consulted by the resolver for every route target of that model. The range is fixed platform policy (TOTAL_REQUEST_TIMEOUT_MIN_SECS..=TOTAL_REQUEST_TIMEOUT_MAX_SECS), enforced by the column CHECK.

stream_idle_timeout_secs
integer<int32> | null

Per-mapping stream-idle (per-chunk) timeout for streaming responses. Defaults to STREAM_IDLE_TIMEOUT_DEFAULT_SECS at insert; enforced via tokio::time::timeout around each upstream SSE/eventstream chunk read. The range is fixed platform policy (STREAM_IDLE_TIMEOUT_MIN_SECS..=STREAM_IDLE_TIMEOUT_MAX_SECS), enforced by the column CHECK.