Skip to main content
PUT
Update a provider

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.

Path Parameters

id
string<uuid>
required

Identifier, a UUID

Body

application/json
api_key
string | null
auth_type
string | null
base_url
string | null
billing_mode
enum<string> | null

None (omitted) leaves the billing mode unchanged (BCP-3876).

Changing this is not retroactive: cost is resolved at request time, so events already recorded keep the cost they were recorded with. The UI confirms that before saving.

Available options:
per_token,
not_metered
billing_note
string | null

None (omitted) leaves the note unchanged; Some(None) clears it.

billing_reason
enum<string> | null

None (omitted) leaves the reason unchanged; Some(None) (JSON null) clears it, which is only valid while the provider is (or is becoming) per_token. Deserialized tri-state for the same reason connection_id is: serde would otherwise collapse null and missing, so clearing a reason would be indistinguishable from not mentioning it.

Available options:
subscription,
local,
external,
other
change_note
string | null

Optional free-text note explaining why this edit was made (BCP-3998).

Deliberately not tri-state like billing_note directly above, and the contrast is the point: a billing note describes a standing arrangement, so omitting it must leave it alone. A change note describes one edit, so omitting it clears the previous one — otherwise an unrelated later edit would inherit an explanation written for a different change.

connection_id
string<uuid> | null

None (field omitted) leaves connection_id unchanged. Some(None) (JSON null) clears the connection, switching the provider back to per-provider direct credentials. Some(Some(id)) (re)binds the provider to a shared connection. Without the custom deserializer below, serde would collapse the null and missing cases to None, leaving the provider silently bound to its previous shared credential even when the UI shows "Direct".

credentials
any
enabled
boolean | null
enforce_health_check
boolean | null

None (omitted) leaves the health-gate override unchanged. Some(true) enforces the gate; Some(false) bypasses it so the provider serves even when its connectivity probe is failing.

model_sync_mode
enum<string> | null

None (omitted) leaves the catalog-sync mode unchanged (BCP-3811).

Available options:
off,
additive,
full
name
string | null
request_timeout_secs
integer<int32> | null

None (omitted) leaves the column unchanged. Some(None) (JSON null) clears the provider-tier override. Some(Some(secs)) sets it; the range is fixed platform policy (TOTAL_REQUEST_TIMEOUT_MIN_SECS..=TOTAL_REQUEST_TIMEOUT_MAX_SECS, see [crate::proxy::timeouts]).

settings
any
stream_idle_timeout_secs
integer<int32> | null

None (omitted) leaves the column unchanged. Some(None) (JSON null) clears the provider-tier override. Some(Some(secs)) sets it; the range is fixed platform policy (STREAM_IDLE_TIMEOUT_MIN_SECS..=STREAM_IDLE_TIMEOUT_MAX_SECS, see [crate::proxy::timeouts]).

Response

The requested record

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

Absent in the resolve/route queries -- the request path never reads it -- and read with try_get, so those rows come back unattributed rather than failing. That is indistinguishable from a row nobody has touched since V75, which is the correct thing for a value the request path was never given.

auth_type
string
required
base_url
string
required
billing_mode
enum<string>
required

Whether the gateway records a per-token cost for this provider's traffic (V69 / BCP-3876). PerToken for every provider that has not opted in, which is the default and the back-compat value.

The request path does not read this field: billing consults [ai_governance::CostCalculator]'s own cached not-metered set, which is refreshed from the same query as pricing. This exists for the admin API surface and the audit trail.

Available options:
per_token,
not_metered
created_at
string<date-time>
required
enabled
boolean
required
enforce_health_check
boolean
required

Operator override for the health gate (V46). When true (default) routing requires health_status <> 'unhealthy'; when false the gate is bypassed and the provider serves regardless of probe results (we still probe and surface health). Lets an admin force traffic through a false-positive probe.

health_status
string
required

Observed upstream reachability, recorded separately from enabled (operator intent) so the system never overwrites the toggle (V45). One of unverified | healthy | unhealthy. unverified is the back-compat default and also covers provider families we don't probe (Bedrock/Vertex/Azure, claude_oauth, codex_oauth). A provider serves traffic only when enabled AND health_status <> 'unhealthy': a failed probe auto-suspends it from routing (see resolve_*) without disabling it, and it resumes once a probe records it healthy again.

id
string<uuid>
required
model_provider
string
required
model_sync_mode
enum<string>
required

Whether this provider tracks Barndoor's model catalog, and how far (V63 / BCP-3811). Off for every provider that has not opted in, which is the default and the back-compat value.

Available options:
off,
additive,
full
name
string
required
org_id
string<uuid>
required
secret_path
string
required
settings
any
required
updated_at
string<date-time>
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
billing_note
string | null

Optional free-text context for the arrangement (max 200 chars). Human-readable only — never parsed, never aggregated.

billing_reason
enum<string> | null

How the vendor bills this provider. Required when billing_mode is NotMetered, optional otherwise (V69 CHECK-enforced) — a subscription billing overages is both per-token and a subscription. Purely descriptive: no code branches on it, which is what lets a new reason be added without touching the billing path.

Available options:
subscription,
local,
external,
other
catalog_id
string<uuid> | null
catalog_slug
string | null
connection_id
string<uuid> | null
health_checked_at
string<date-time> | null

When the last connectivity probe ran (NULL until the first probe).

health_detail
string | null

Reason for the last unhealthy or unverified probe (NULL if healthy or never probed).

request_timeout_secs
integer<int32> | null

Provider-tier total-request timeout override (non-streaming). Operator-only and None by default: the effective value is written at the route tier (model_mappings), so this only applies if a route row somehow leaves it unset. Range TOTAL_REQUEST_TIMEOUT_MIN_SECS..=TOTAL_REQUEST_TIMEOUT_MAX_SECS is enforced by the CHECK constraint (see proxy::timeouts).

stream_idle_timeout_secs
integer<int32> | null

Provider-tier stream-idle timeout override (streaming). Operator-only and None by default; the effective value is written at the route tier (model_mappings). Range STREAM_IDLE_TIMEOUT_MIN_SECS..=STREAM_IDLE_TIMEOUT_MAX_SECS is enforced by the CHECK constraint (see proxy::timeouts).