Routing and failover API
Configure the same routing and failover that the Policy Engine's Model routing card owns, as typed resources: a route sends a requested model to a destination, a destination is a weighted pool or an ordered list of provider models, and failover says where a failed request may go. You never write QuilrQL. Each write is validated, turned into policy rules for you, and published as one policy revision. For what routing and failover do at runtime, see Routing and failover.
routing:read does not need read. Try every operation with your own key in the Management API playground.
Before you start
- The Policy Engine must be on for the LLM Gateway. While it is off, every call answers
409 policy_not_enabled.GET /capabilitiesreportsmanaged_controls.enabledand which collections are available. - Issue a key with
routing:readandrouting:write(addrouting:constraintsfor constraints). See Scopes. - Provider labels in destinations and failover must be shared providers or provider labels of an app. Unknown labels are
422 invalid_named_reference.
How a request is routed
The resources map onto the gateway's routing steps. Routing constraints and model access are not a step of their own: they filter every candidate, at selection and at every failover tier.
POST /openai_compatible/v1/chat/completions
{ "model": "smart", "messages": [...] }
app: support-bot user: dana@example.comA tier is used only when the tiers before it have no usable candidate left. The failover object's scope (route, same_model or app) is how far down this list a request may go. On reads it is also returned as candidate_scope, so it is not confused with the resource scope (apps, smart groups, users, app tags).
Who owns a request's failover
- Does the deciding route have its own failover?yes:Route failoverfailover_owner.kind: route
- Does a failover rule match the request?Highest rank firstyes:Failover rulekind: failover_rule
- Is a failover default set?yes:Failover defaultkind: failover_default
- None of the aboveBuilt-in defaultkind: built_in_default
The winner supplies the whole failover object; settings from different levels are not merged. failover on a route, rule or default is either inline settings or {"ref": "<profile id>"}. A profile in use cannot be deleted (409 failover_profile_in_use), and neither can a destination (409 destination_in_use).
Rank and precedence
- Higher rank wins where routes overlap. Ranks go from 1 to 9999. Omit
rankon create and the API assigns the highest overlapping rank plus 10, returned withrank_source: "assigned". - Routes and failover rules share one rank space. An overlapping route and failover rule cannot have the same rank (
422 route_rank_conflict, listing the conflicts). - Overlap is decided by literals. Two rules are disjoint only when their app lists, requested-model lists or client API lists (
surface_familyas a list) cannot intersect. Scopes made only of smart groups, users or app tags always overlap, because membership changes, so they need different ranks. - Console rules. API-managed routes sit at Policy Engine priority 400. A console routing rule at a higher priority overrides them where it overlaps (write warning
console_overrides_managed); a lower one loses; one at 400 takes part in the rank check. Routing constraints accumulate and have no rank. - Route reads carry
shadowed_by: the higher-ranked routes and console rules that win where they overlap, withcoverage: full(this route never routes) orpartial.
Worked example. One tenant, three managed rules:
- An
eu-staffuser asking forsmartmatches both routes:eu-smart(120) wins./routing/effectivelistssmart-defaultundershadowed, andsmart-defaultreadsshadowed_by: [{route_id: "eu-smart", coverage: "partial"}]. - Another
eu-staffroute forsmartat rank 120 is422 route_rank_conflict; omit the rank to get 130. - A failover rule for
eu-staffat rank 120 also conflicts (shared rank space); 30 is fine. - If
eu-smarthas no failover of its own,eu-staff-failoversupplies it (failover_owner.kind: failover_rule). If it has one, the route's wins (kind: route).
Writes, versions and idempotency
Ids match ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$. Lists take limit (1-500, default 100), cursor, and filters source, app, requested_model, mode and references=<provider_label>[/<model>]. A cursor read after another publish is 409 collection_changed; restart from the first page.
Every write response carries revision, changed, resource, etag, warnings, impact, operation_id and propagation {poll_seconds, status, session_pins}.
Routes: mode and client APIs
modeisactive,observe(evaluated and reported, never routes) ordisabled(kept, not applied).enabled: falseis an alias fordisabled.POST /controls/routes/{id}:set-modeswitches it without resending the route.surface_familynames the client API family:chat_completion,anthropic_messages,vertex_ai,responses,realtimeorbedrock_runtime. It is required for weighted destinations. A list makes one rule per family, each matching only that API;chat_completionandanthropic_messagescannot share a list (422 surface_family_overlap).session.route_decisionisper_conversation(default) orper_message.
Conversations and repin
Routing changes apply to new conversations. An existing conversation stays on its pinned target while that target is still eligible: a weight change, or adding members to a destination, keeps it (propagation.session_pins: "kept"). Removing a member from the destination, or a change that makes the pinned target unusable, re-routes those conversations on their next request.
To move existing conversations too, send ?repin=drop on the write. It drops the session pins of the affected apps once per operation and reports session_pins: "dropped". A change that is not limited to named apps would drop every pin of the tenant; that needs ?repin=drop&repin_scope=tenant, otherwise 422 repin_scope_confirmation_required. A dry run shows the apps under impact.pins.apps ("*" for every app).
A dropped conversation routes again and its next request starts with a cold provider prompt cache. Prefer repin=keep (the default) unless existing conversations must move now.
Check that a change is live
- Rollout.
GET /controls/revisions/{revision}/statuscounts gateway processes that served the tenant in the last hour:processes_reporting,processes_on_rev,lagging, andcomplete(at least one reports and none lags).processes_reporting: 0means no recent traffic, not "not applied"; an idle gateway picks the revision up on its next request. - Explain.
GET /routing/effective?app=&requested_model=&user=&surface=shows the route that wins, its destination,failover_ownerand resolved failover, the rules it outranked (shadowed), constraints, candidates left and active mark-downs, for the evaluated revision (revision_current). Nothing is sent upstream. - Test a proposal.
POST /routing/testruns the routing dry run for a sample body, optionally withproposedcontrols ({collection: {id: resource | null}}) rendered in memory. Nothing is published, pinned or sent upstream.POST /routing/target-checksays whether each provider model can serve each client API (native, converted or not at all). - Watch traffic.
GET /routing/summaryshows traffic per route and destination member against its weight;GET /failover/summaryshows retries, failovers and outcomes per target.
Revision history and restore
GET /controls/revisions lists revisions newest first with actor, operation_id, kind (managed, console, budgets, restore, ...) and domains_changed. GET /controls/revisions/{revision}/resources/{collection}/{id} reads one resource as it was.
POST /controls/revisions/{revision}:restore puts the managed collections (all that differ, or the ones in domains) back to that revision, in one new revision. Console rules are untouched. It needs If-Match with the collection ETag "r<active revision>", an Idempotency-Key (unless dry_run), and the write scope of every restored collection. If a restored resource would fail validation now, for example it names a deleted provider, the restore is 409 restore_conflict with problems; a dry run shows the same list.
Workflows
Set these once. Responses are JSON; the examples use jq to read ETags.
export API="$MANAGEMENT_URL/llmgateway/management/v1"
auth=(-H "Authorization: Bearer $MANAGEMENT_KEY" -H 'Content-Type: application/json')
Day 0: a model alias with a fallback
Clients ask for smart; it is served by Azure, with the mini model as backup. The requested model must be allowed for the app; if the app restricts models, add a model access rule that allows smart.
# 1. Where "smart" goes: an ordered target list
curl -X PUT "$API/controls/destinations/smart-pool" "${auth[@]}" \
-d '{"type": "ordered", "targets": [{"provider_label": "azure-eu", "model": "gpt-4.1"}]}'
# 2. How it fails over: two tries, then the mini model, then the same model elsewhere
curl -X PUT "$API/controls/failover-profiles/standard" "${auth[@]}" \
-d '{"scope": "same_model", "max_attempts": 2, "fallbacks": [{"provider_label": "azure-eu", "model": "gpt-4.1-mini"}]}'
# 3. Preview the route, then publish it
body='{"match": {"requested_models": ["smart"]}, "scope": {"apps": ["support-bot"]},
"destination": {"ref": "smart-pool"}, "failover": {"ref": "standard"}, "mode": "active"}'
curl -X PUT "$API/controls/routes/smart?dry_run=true" "${auth[@]}" -d "$body" | jq '{diff, warnings, impact}'
curl -X PUT "$API/controls/routes/smart" "${auth[@]}" -d "$body" | jq '{revision, etag, propagation}'
# 4. Confirm
curl "$API/routing/effective?app=support-bot&requested_model=smart" "${auth[@]}" | jq '{route, destination, failover_owner}'
Steps 1 to 3 can be one revision with POST /controls/_batch.
Gradual migration: 5%, 50%, 100%, with abort
Move chat-pool from azure-eu to bedrock-eu. Record the revision before you start; it is your abort point.
START=$(curl -s "$API/controls/revisions?limit=1" "${auth[@]}" | jq -r .active_revision)
# 5%: add the new member (adding a member keeps existing conversations where they are)
ETAG=$(curl -s "$API/controls/destinations/chat-pool" "${auth[@]}" | jq -r .etag)
curl -X PUT "$API/controls/destinations/chat-pool" "${auth[@]}" -H "If-Match: $ETAG" \
-d '{"type": "weighted", "members": [{"provider_label": "azure-eu", "model": "gpt-4.1", "weight": 95},
{"provider_label": "bedrock-eu", "model": "anthropic.claude-sonnet-4", "weight": 5}]}'
# 50%: check /routing/summary and /failover/summary, then change only the weights
ETAG=$(curl -s "$API/controls/destinations/chat-pool" "${auth[@]}" | jq -r .etag)
curl -X POST "$API/controls/destinations/chat-pool:set-weights" "${auth[@]}" \
-H "If-Match: $ETAG" -H "Idempotency-Key: chat-pool-50" \
-d '{"members": [{"provider_label": "azure-eu", "model": "gpt-4.1", "weight": 50},
{"provider_label": "bedrock-eu", "model": "anthropic.claude-sonnet-4", "weight": 50}]}'
# 100%: replace the destination with the new member only (conversations on azure-eu route again)
ETAG=$(curl -s "$API/controls/destinations/chat-pool" "${auth[@]}" | jq -r .etag)
curl -X PUT "$API/controls/destinations/chat-pool" "${auth[@]}" -H "If-Match: $ETAG" \
-d '{"type": "weighted", "members": [{"provider_label": "bedrock-eu", "model": "anthropic.claude-sonnet-4", "weight": 100}]}'
# Abort at any step: put destinations back to the starting revision
COLL=$(curl -s "$API/controls/revisions?limit=1" "${auth[@]}" | jq -r '"\"r\(.active_revision)\""')
curl -X POST "$API/controls/revisions/$START:restore" "${auth[@]}" \
-H "If-Match: $COLL" -H "Idempotency-Key: chat-pool-abort" -d '{"domains": ["destinations"]}'
Weights must total 100 and each weight must be above 0. Add ?repin=drop to a step if conversations already running should follow the new weights immediately.
Provider swap with replace-member
Swap one provider model for another in a destination, and so in every route that uses it, in one revision:
ETAG=$(curl -s "$API/controls/destinations/eu-pool" "${auth[@]}" | jq -r .etag)
curl -X POST "$API/controls/destinations/eu-pool:replace-member?dry_run=true" "${auth[@]}" \
-H "If-Match: $ETAG" -H "Idempotency-Key: swap-bedrock-eu" \
-d '{"from": {"provider_label": "bedrock-eu", "model": "anthropic.claude-sonnet-4"},
"to": {"provider_label": "azure-eu", "model": "gpt-4.1-mini"}}' | jq '{diff, impact}'
# Same call without dry_run=true to publish. "from" must be a member (422 member_not_found).
Find everything that uses a provider
Before deleting, renaming or rotating a provider, list every control and console rule that names it (or one of its models), following destination and failover-profile references:
curl "$API/controls/references?provider_label=azure-eu" "${auth[@]}" | jq '.items[] | {collection, id, source, fields}'
# Narrow a list instead: GET /controls/routes?references=azure-eu/gpt-4.1
With limits:read the answer also includes rate limits and model limits.
Undo a change with restore
curl "$API/controls/revisions?limit=5" "${auth[@]}" | jq '.items[] | {revision, kind, domains_changed, actor}'
COLL=$(curl -s "$API/controls/revisions?limit=1" "${auth[@]}" | jq -r '"\"r\(.active_revision)\""')
curl -X POST "$API/controls/revisions/41:restore?dry_run=true" "${auth[@]}" -H "If-Match: $COLL" -d '{"domains": ["routes"]}'
curl -X POST "$API/controls/revisions/41:restore" "${auth[@]}" -H "If-Match: $COLL" \
-H "Idempotency-Key: undo-routes-41" -d '{"domains": ["routes"]}'
Errors
Endpoints
Destinations
/controls/destinationsList destinations
Every managed destination with its ETag, then the console policy rules of the same kind as read-only rows (source console, policy, rule_index, view). Console rows cannot be written here (409 rule_not_api_managed). Paginated (limit, cursor bound to the revision) and filtered by source, app, requested_model, mode and references.
routing:readPath, query & header parameters 7
limit (query)integeroptionalPage size.
cursor (query)stringoptionalnext_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).
source (query)objectoptionalOnly managed resources or only console rows.
"managed""console"app (query)stringoptionalRows that can apply to this app (rows scoped only by smart group, user or tag are kept). app_name is a deprecated alias.
requested_model (query)stringoptionalRows that can apply to this requested model. model is a deprecated alias.
mode (query)stringoptionalRows with this mode (routes: active, observe, disabled; limits: enforce, alert, paused).
references (query)stringoptional<provider_label> or <provider_label>/<model>: rows that name it, following destination and failover-profile refs (adds references [paths]).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/destinations?limit=example' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/destinations/{resource_id}Delete a destination
Removes the destination; refused while other controls reference it. If-Match is required.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Unknown fields are rejected in this object.
curl --request DELETE \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/destinations/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/destinations/{resource_id}Read a destination
One destination and its ETag.
routing:readPath, query & header parameters 1
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/destinations/eu-pool' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/destinations/{resource_id}Update a destination
JSON merge patch of the destination (null removes a field); the result is validated as a whole. If-Match is required. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Variant 1 object
descriptionstringoptionalmembersarray<object>requiredArray item specification
modelstringrequiredprovider_labelstringrequiredweightnumberrequiredUnknown fields are rejected in this object.
modeobjectoptional"request_count""token"type"weighted"requiredVariant 2 object
descriptionstringoptionaltargetsarray<object>requiredArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
type"ordered"requiredcurl --request PATCH \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/destinations/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/destinations/{resource_id}Create or replace a destination
Creates (201) or replaces (200) the destination. Changing an existing one needs If-Match; If-None-Match: * creates only. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 7
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringoptionalResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
If-None-Match (header)"*"optionalCreate only: 412 when the resource exists with different content.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Variant 1 object
descriptionstringoptionalmembersarray<object>requiredArray item specification
modelstringrequiredprovider_labelstringrequiredweightnumberrequiredUnknown fields are rejected in this object.
modeobjectoptional"request_count""token"type"weighted"requiredVariant 2 object
descriptionstringoptionaltargetsarray<object>requiredArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
type"ordered"requiredcurl --request PUT \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/destinations/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Content-Type: application/json' \
--data '{
"members": [
{
"model": "gpt-4.1",
"provider_label": "azure-eu",
"weight": 70
},
{
"model": "anthropic.claude-sonnet-4",
"provider_label": "bedrock-eu",
"weight": 30
}
],
"mode": "request_count",
"type": "weighted"
}'
Authentication, errors & retry rules Try it in the playground
/controls/destinations/{resource_id}:replace-memberReplace member of a destination
Swaps one provider/model for another in the destination, and so in every route that uses it. If-Match and Idempotency-Key are required; changed false when nothing changes.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringrequiredUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Not needed with dry_run=true.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
fromobjectrequiredObject fields
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
toobjectrequiredObject fields
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
curl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/destinations/eu-pool:replace-member' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Idempotency-Key: eu-routing-change-001' \
--header 'Content-Type: application/json' \
--data '{
"from": {
"model": "anthropic.claude-sonnet-4",
"provider_label": "bedrock-eu"
},
"to": {
"model": "gpt-4.1-mini",
"provider_label": "azure-eu"
}
}'
Authentication, errors & retry rules Try it in the playground
/controls/destinations/{resource_id}:set-weightsSet weights of a destination
Replaces the members' weights (they must total 100); every route that uses the destination changes in the same revision. New conversations use the new weights; existing ones keep their pin unless repin=drop. If-Match and Idempotency-Key are required; changed false when nothing changes.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringrequiredUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Not needed with dry_run=true.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
membersarray<object>requiredArray item specification
modelstringrequiredprovider_labelstringrequiredweightnumberrequiredUnknown fields are rejected in this object.
curl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/destinations/eu-pool:set-weights' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Idempotency-Key: eu-routing-change-001' \
--header 'Content-Type: application/json' \
--data '{
"members": [
{
"model": "gpt-4.1",
"provider_label": "azure-eu",
"weight": 50
},
{
"model": "anthropic.claude-sonnet-4",
"provider_label": "bedrock-eu",
"weight": 50
}
]
}'
Authentication, errors & retry rules Try it in the playground
Routes
/controls/routesList routes
Every managed route with its ETag, then the console policy rules of the same kind as read-only rows (source console, policy, rule_index, view). Console rows cannot be written here (409 rule_not_api_managed). Paginated (limit, cursor bound to the revision) and filtered by source, app, requested_model, mode and references.
routing:readPath, query & header parameters 7
limit (query)integeroptionalPage size.
cursor (query)stringoptionalnext_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).
source (query)objectoptionalOnly managed resources or only console rows.
"managed""console"app (query)stringoptionalRows that can apply to this app (rows scoped only by smart group, user or tag are kept). app_name is a deprecated alias.
requested_model (query)stringoptionalRows that can apply to this requested model. model is a deprecated alias.
mode (query)stringoptionalRows with this mode (routes: active, observe, disabled; limits: enforce, alert, paused).
references (query)stringoptional<provider_label> or <provider_label>/<model>: rows that name it, following destination and failover-profile refs (adds references [paths]).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routes?limit=example' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/routes/{resource_id}Delete a route
Removes the route; refused while other controls reference it. If-Match is required.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Unknown fields are rejected in this object.
curl --request DELETE \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routes/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/routes/{resource_id}Read a route
One route and its ETag.
routing:readPath, query & header parameters 1
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routes/eu-pool' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/routes/{resource_id}Update a route
JSON merge patch of the route (null removes a field); the result is validated as a whole. If-Match is required. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
descriptionstringoptionaldestinationone of 2 variantsrequiredVariant 1 object
refstringrequiredUnknown fields are rejected in this object.
Variant 2 one of 2 variants
Variant 1 object
descriptionstringoptionalmembersarray<object>requiredArray item specification
modelstringrequiredprovider_labelstringrequiredweightnumberrequiredUnknown fields are rejected in this object.
modeobjectoptional"request_count""token"type"weighted"requiredVariant 2 object
descriptionstringoptionaltargetsarray<object>requiredArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
type"ordered"requiredenabledbooleanoptionalAlias of mode: false = disabled, true re-enables a disabled route as active. Sent together with mode, the two must agree.
failoverone of 2 variantsoptionalThe route's whole failover object; omitted = the matching failover rule, else the tenant default.
Variant 1 object
refstringrequiredUnknown fields are rejected in this object.
Variant 2 object
attempt_timeout_msintegeroptionalcandidate_scopeobjectoptionalAlias of scope (the candidate tier); returned on reads.
"route""same_model""app"capabilitiesobjectoptionalenabledbooleanoptionalfallbacksarray<object>optionalArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
max_attemptsintegeroptionalonarray<object>optionalArray item specification
objectValues: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"
preferencearray<string>optionalArray item specification
stringsame_target_retriesintegeroptionalscopeobjectoptionalCandidate tier: how far failover may look for another target (not the resource scope).
"route""same_model""app"total_timeout_msintegeroptionalUnknown fields are rejected in this object.
matchobjectoptionalObject fields
requested_modelsarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
modeobjectoptional"active""observe""disabled"rankintegeroptionalOrder among overlapping managed routes and failover rules (higher wins; console policies with a higher priority than managed controls override them); omitted = max(overlapping) + 10, returned with rank_source assigned.
scopeobjectoptionalEvery non-empty list must match (AND); empty lists do not restrict.
Object fields
app_tagsarray<string>optionalArray item specification
stringappsarray<string>optionalArray item specification
stringsmart_groupsarray<string>optionalArray item specification
stringusersarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
sessionobjectoptionalObject fields
route_decisionobjectoptional"per_conversation""per_message"surface_familyone of 2 variantsoptionalThe client API family the route serves; required for weighted destinations. A list makes one rule per family, each limited to that family's client API (chat_completion and anthropic_messages cannot share a list).
Variant 1 object
objectValues: "chat_completion""anthropic_messages""vertex_ai""responses""realtime""bedrock_runtime"
Variant 2 array<object>
array<object>curl --request PATCH \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routes/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/routes/{resource_id}Create or replace a route
Creates (201) or replaces (200) the route. Changing an existing one needs If-Match; If-None-Match: * creates only. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 7
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringoptionalResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
If-None-Match (header)"*"optionalCreate only: 412 when the resource exists with different content.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
descriptionstringoptionaldestinationone of 2 variantsrequiredVariant 1 object
refstringrequiredUnknown fields are rejected in this object.
Variant 2 one of 2 variants
Variant 1 object
descriptionstringoptionalmembersarray<object>requiredArray item specification
modelstringrequiredprovider_labelstringrequiredweightnumberrequiredUnknown fields are rejected in this object.
modeobjectoptional"request_count""token"type"weighted"requiredVariant 2 object
descriptionstringoptionaltargetsarray<object>requiredArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
type"ordered"requiredenabledbooleanoptionalAlias of mode: false = disabled, true re-enables a disabled route as active. Sent together with mode, the two must agree.
failoverone of 2 variantsoptionalThe route's whole failover object; omitted = the matching failover rule, else the tenant default.
Variant 1 object
refstringrequiredUnknown fields are rejected in this object.
Variant 2 object
attempt_timeout_msintegeroptionalcandidate_scopeobjectoptionalAlias of scope (the candidate tier); returned on reads.
"route""same_model""app"capabilitiesobjectoptionalenabledbooleanoptionalfallbacksarray<object>optionalArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
max_attemptsintegeroptionalonarray<object>optionalArray item specification
objectValues: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"
preferencearray<string>optionalArray item specification
stringsame_target_retriesintegeroptionalscopeobjectoptionalCandidate tier: how far failover may look for another target (not the resource scope).
"route""same_model""app"total_timeout_msintegeroptionalUnknown fields are rejected in this object.
matchobjectoptionalObject fields
requested_modelsarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
modeobjectoptional"active""observe""disabled"rankintegeroptionalOrder among overlapping managed routes and failover rules (higher wins; console policies with a higher priority than managed controls override them); omitted = max(overlapping) + 10, returned with rank_source assigned.
scopeobjectoptionalEvery non-empty list must match (AND); empty lists do not restrict.
Object fields
app_tagsarray<string>optionalArray item specification
stringappsarray<string>optionalArray item specification
stringsmart_groupsarray<string>optionalArray item specification
stringusersarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
sessionobjectoptionalObject fields
route_decisionobjectoptional"per_conversation""per_message"surface_familyone of 2 variantsoptionalThe client API family the route serves; required for weighted destinations. A list makes one rule per family, each limited to that family's client API (chat_completion and anthropic_messages cannot share a list).
Variant 1 object
objectValues: "chat_completion""anthropic_messages""vertex_ai""responses""realtime""bedrock_runtime"
Variant 2 array<object>
array<object>curl --request PUT \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routes/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Content-Type: application/json' \
--data '{
"description": "EU staff smart alias",
"destination": {
"ref": "eu-pool"
},
"failover": {
"ref": "standard"
},
"match": {
"requested_models": [
"smart"
]
},
"mode": "active",
"rank": 120,
"scope": {
"apps": [
"support-bot"
],
"smart_groups": [
"eu-staff"
]
},
"session": {
"route_decision": "per_conversation"
},
"surface_family": "chat_completion"
}'
Authentication, errors & retry rules Try it in the playground
/controls/routes/{resource_id}:set-modeSet mode of a route
active routes traffic, observe evaluates the route without routing (shadow), disabled keeps the route but removes its rule. If-Match and Idempotency-Key are required; changed false when nothing changes.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringrequiredUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Not needed with dry_run=true.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
modeobjectrequired"active""observe""disabled"curl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routes/eu-pool:set-mode' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Idempotency-Key: eu-routing-change-001' \
--header 'Content-Type: application/json' \
--data '{
"mode": "observe"
}'
Authentication, errors & retry rules Try it in the playground
Failover
/controls/failover-defaultReset the failover default
Removes it, so the built-in default applies. If-Match is required.
routing:writePath, query & header parameters 5
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Unknown fields are rejected in this object.
curl --request DELETE \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-default' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/failover-defaultRead the failover default
One failover default and its ETag. resource is null while the built-in default applies.
routing:readNo request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-default' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/failover-defaultCreate or replace the failover default
Creates (201) or replaces (200) the failover default. Changing an existing one needs If-Match; If-None-Match: * creates only. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 6
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringoptionalResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
If-None-Match (header)"*"optionalCreate only: 412 when the resource exists with different content.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Tenant singleton; DELETE resets to the built-in default.
descriptionstringoptionalfailoverone of 2 variantsrequiredVariant 1 object
refstringrequiredUnknown fields are rejected in this object.
Variant 2 object
attempt_timeout_msintegeroptionalcandidate_scopeobjectoptionalAlias of scope (the candidate tier); returned on reads.
"route""same_model""app"capabilitiesobjectoptionalenabledbooleanoptionalfallbacksarray<object>optionalArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
max_attemptsintegeroptionalonarray<object>optionalArray item specification
objectValues: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"
preferencearray<string>optionalArray item specification
stringsame_target_retriesintegeroptionalscopeobjectoptionalCandidate tier: how far failover may look for another target (not the resource scope).
"route""same_model""app"total_timeout_msintegeroptionalUnknown fields are rejected in this object.
curl --request PUT \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-default' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Content-Type: application/json' \
--data '{
"failover": {
"max_attempts": 2,
"scope": "same_model"
}
}'
Authentication, errors & retry rules Try it in the playground
/controls/failover-profilesList failover profiles
Every managed failover profile with its ETag, then the console policy rules of the same kind as read-only rows (source console, policy, rule_index, view). Console rows cannot be written here (409 rule_not_api_managed). Paginated (limit, cursor bound to the revision) and filtered by source, app, requested_model, mode and references.
routing:readPath, query & header parameters 7
limit (query)integeroptionalPage size.
cursor (query)stringoptionalnext_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).
source (query)objectoptionalOnly managed resources or only console rows.
"managed""console"app (query)stringoptionalRows that can apply to this app (rows scoped only by smart group, user or tag are kept). app_name is a deprecated alias.
requested_model (query)stringoptionalRows that can apply to this requested model. model is a deprecated alias.
mode (query)stringoptionalRows with this mode (routes: active, observe, disabled; limits: enforce, alert, paused).
references (query)stringoptional<provider_label> or <provider_label>/<model>: rows that name it, following destination and failover-profile refs (adds references [paths]).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-profiles?limit=example' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/failover-profiles/{resource_id}Delete a failover profile
Removes the failover profile; refused while other controls reference it. If-Match is required.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Unknown fields are rejected in this object.
curl --request DELETE \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-profiles/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/failover-profiles/{resource_id}Read a failover profile
One failover profile and its ETag.
routing:readPath, query & header parameters 1
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-profiles/eu-pool' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/failover-profiles/{resource_id}Update a failover profile
JSON merge patch of the failover profile (null removes a field); the result is validated as a whole. If-Match is required. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
A failover object: how the gateway retries and where it may move a failed request.
attempt_timeout_msintegeroptionalcandidate_scopeobjectoptionalAlias of scope (the candidate tier); returned on reads.
"route""same_model""app"capabilitiesobjectoptionaldescriptionstringoptionalenabledbooleanoptionalfallbacksarray<object>optionalArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
max_attemptsintegeroptionalonarray<object>optionalArray item specification
objectValues: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"
preferencearray<string>optionalArray item specification
stringsame_target_retriesintegeroptionalscopeobjectoptionalCandidate tier: how far failover may look for another target (not the resource scope).
"route""same_model""app"total_timeout_msintegeroptionalUnknown fields are rejected in this object.
curl --request PATCH \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-profiles/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/failover-profiles/{resource_id}Create or replace a failover profile
Creates (201) or replaces (200) the failover profile. Changing an existing one needs If-Match; If-None-Match: * creates only. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 7
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringoptionalResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
If-None-Match (header)"*"optionalCreate only: 412 when the resource exists with different content.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
A failover object: how the gateway retries and where it may move a failed request.
attempt_timeout_msintegeroptionalcandidate_scopeobjectoptionalAlias of scope (the candidate tier); returned on reads.
"route""same_model""app"capabilitiesobjectoptionaldescriptionstringoptionalenabledbooleanoptionalfallbacksarray<object>optionalArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
max_attemptsintegeroptionalonarray<object>optionalArray item specification
objectValues: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"
preferencearray<string>optionalArray item specification
stringsame_target_retriesintegeroptionalscopeobjectoptionalCandidate tier: how far failover may look for another target (not the resource scope).
"route""same_model""app"total_timeout_msintegeroptionalUnknown fields are rejected in this object.
curl --request PUT \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-profiles/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Content-Type: application/json' \
--data '{
"description": "Two tries, then the mini model",
"fallbacks": [
{
"model": "gpt-4.1-mini",
"provider_label": "azure-eu"
}
],
"max_attempts": 2,
"scope": "route"
}'
Authentication, errors & retry rules Try it in the playground
/controls/failover-rulesList failover rules
Every managed failover rule with its ETag, then the console policy rules of the same kind as read-only rows (source console, policy, rule_index, view). Console rows cannot be written here (409 rule_not_api_managed). Paginated (limit, cursor bound to the revision) and filtered by source, app, requested_model, mode and references.
routing:readPath, query & header parameters 7
limit (query)integeroptionalPage size.
cursor (query)stringoptionalnext_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).
source (query)objectoptionalOnly managed resources or only console rows.
"managed""console"app (query)stringoptionalRows that can apply to this app (rows scoped only by smart group, user or tag are kept). app_name is a deprecated alias.
requested_model (query)stringoptionalRows that can apply to this requested model. model is a deprecated alias.
mode (query)stringoptionalRows with this mode (routes: active, observe, disabled; limits: enforce, alert, paused).
references (query)stringoptional<provider_label> or <provider_label>/<model>: rows that name it, following destination and failover-profile refs (adds references [paths]).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-rules?limit=example' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/failover-rules/{resource_id}Delete a failover rule
Removes the failover rule; refused while other controls reference it. If-Match is required.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Unknown fields are rejected in this object.
curl --request DELETE \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-rules/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/failover-rules/{resource_id}Read a failover rule
One failover rule and its ETag.
routing:readPath, query & header parameters 1
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-rules/eu-pool' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/failover-rules/{resource_id}Update a failover rule
JSON merge patch of the failover rule (null removes a field); the result is validated as a whole. If-Match is required. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
descriptionstringoptionalenabledbooleanoptionalfailoverone of 2 variantsrequiredVariant 1 object
refstringrequiredUnknown fields are rejected in this object.
Variant 2 object
attempt_timeout_msintegeroptionalcandidate_scopeobjectoptionalAlias of scope (the candidate tier); returned on reads.
"route""same_model""app"capabilitiesobjectoptionalenabledbooleanoptionalfallbacksarray<object>optionalArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
max_attemptsintegeroptionalonarray<object>optionalArray item specification
objectValues: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"
preferencearray<string>optionalArray item specification
stringsame_target_retriesintegeroptionalscopeobjectoptionalCandidate tier: how far failover may look for another target (not the resource scope).
"route""same_model""app"total_timeout_msintegeroptionalUnknown fields are rejected in this object.
matchobjectoptionalObject fields
requested_modelsarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
rankintegeroptionalOrder among overlapping managed routes and failover rules (higher wins; console policies with a higher priority than managed controls override them); omitted = max(overlapping) + 10, returned with rank_source assigned.
scopeobjectoptionalEvery non-empty list must match (AND); empty lists do not restrict.
Object fields
app_tagsarray<string>optionalArray item specification
stringappsarray<string>optionalArray item specification
stringsmart_groupsarray<string>optionalArray item specification
stringusersarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
curl --request PATCH \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-rules/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/failover-rules/{resource_id}Create or replace a failover rule
Creates (201) or replaces (200) the failover rule. Changing an existing one needs If-Match; If-None-Match: * creates only. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 7
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringoptionalResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
If-None-Match (header)"*"optionalCreate only: 412 when the resource exists with different content.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
descriptionstringoptionalenabledbooleanoptionalfailoverone of 2 variantsrequiredVariant 1 object
refstringrequiredUnknown fields are rejected in this object.
Variant 2 object
attempt_timeout_msintegeroptionalcandidate_scopeobjectoptionalAlias of scope (the candidate tier); returned on reads.
"route""same_model""app"capabilitiesobjectoptionalenabledbooleanoptionalfallbacksarray<object>optionalArray item specification
modelstringrequiredprovider_labelstringrequiredUnknown fields are rejected in this object.
max_attemptsintegeroptionalonarray<object>optionalArray item specification
objectValues: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"
preferencearray<string>optionalArray item specification
stringsame_target_retriesintegeroptionalscopeobjectoptionalCandidate tier: how far failover may look for another target (not the resource scope).
"route""same_model""app"total_timeout_msintegeroptionalUnknown fields are rejected in this object.
matchobjectoptionalObject fields
requested_modelsarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
rankintegeroptionalOrder among overlapping managed routes and failover rules (higher wins; console policies with a higher priority than managed controls override them); omitted = max(overlapping) + 10, returned with rank_source assigned.
scopeobjectoptionalEvery non-empty list must match (AND); empty lists do not restrict.
Object fields
app_tagsarray<string>optionalArray item specification
stringappsarray<string>optionalArray item specification
stringsmart_groupsarray<string>optionalArray item specification
stringusersarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
curl --request PUT \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/failover-rules/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Content-Type: application/json' \
--data '{
"failover": {
"ref": "standard"
},
"rank": 10,
"scope": {
"smart_groups": [
"eu-staff"
]
}
}'
Authentication, errors & retry rules Try it in the playground
Routing constraints and model access
/controls/model-accessList model access rules
Every managed model access rule with its ETag, then the console policy rules of the same kind as read-only rows (source console, policy, rule_index, view). Console rows cannot be written here (409 rule_not_api_managed). Paginated (limit, cursor bound to the revision) and filtered by source, app, requested_model, mode and references.
routing:readPath, query & header parameters 7
limit (query)integeroptionalPage size.
cursor (query)stringoptionalnext_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).
source (query)objectoptionalOnly managed resources or only console rows.
"managed""console"app (query)stringoptionalRows that can apply to this app (rows scoped only by smart group, user or tag are kept). app_name is a deprecated alias.
requested_model (query)stringoptionalRows that can apply to this requested model. model is a deprecated alias.
mode (query)stringoptionalRows with this mode (routes: active, observe, disabled; limits: enforce, alert, paused).
references (query)stringoptional<provider_label> or <provider_label>/<model>: rows that name it, following destination and failover-profile refs (adds references [paths]).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/model-access?limit=example' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/model-access/{resource_id}Delete a model access rule
Removes the model access rule; refused while other controls reference it. If-Match is required.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Unknown fields are rejected in this object.
curl --request DELETE \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/model-access/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/model-access/{resource_id}Read a model access rule
One model access rule and its ETag.
routing:readPath, query & header parameters 1
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/model-access/eu-pool' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/model-access/{resource_id}Update a model access rule
JSON merge patch of the model access rule (null removes a field); the result is validated as a whole. If-Match is required. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 6
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
allowarray<string>optionalArray item specification
stringdenyarray<string>optionalArray item specification
stringdescriptionstringoptionalscopeobjectoptionalEvery non-empty list must match (AND); empty lists do not restrict.
Object fields
app_tagsarray<string>optionalArray item specification
stringappsarray<string>optionalArray item specification
stringsmart_groupsarray<string>optionalArray item specification
stringusersarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
curl --request PATCH \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/model-access/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/model-access/{resource_id}Create or replace a model access rule
Creates (201) or replaces (200) the model access rule. Changing an existing one needs If-Match; If-None-Match: * creates only. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:writePath, query & header parameters 7
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringoptionalResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
If-None-Match (header)"*"optionalCreate only: 412 when the resource exists with different content.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
allowarray<string>optionalArray item specification
stringdenyarray<string>optionalArray item specification
stringdescriptionstringoptionalscopeobjectoptionalEvery non-empty list must match (AND); empty lists do not restrict.
Object fields
app_tagsarray<string>optionalArray item specification
stringappsarray<string>optionalArray item specification
stringsmart_groupsarray<string>optionalArray item specification
stringusersarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
curl --request PUT \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/model-access/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Content-Type: application/json' \
--data '{
"allow": [
"gpt-4.1"
],
"deny": [
"gpt-4o"
],
"scope": {
"apps": [
"support-bot"
]
}
}'
Authentication, errors & retry rules Try it in the playground
/controls/routing-constraintsList routing constraints
Every managed routing constraint with its ETag, then the console policy rules of the same kind as read-only rows (source console, policy, rule_index, view). Console rows cannot be written here (409 rule_not_api_managed). Paginated (limit, cursor bound to the revision) and filtered by source, app, requested_model, mode and references.
routing:readPath, query & header parameters 7
limit (query)integeroptionalPage size.
cursor (query)stringoptionalnext_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).
source (query)objectoptionalOnly managed resources or only console rows.
"managed""console"app (query)stringoptionalRows that can apply to this app (rows scoped only by smart group, user or tag are kept). app_name is a deprecated alias.
requested_model (query)stringoptionalRows that can apply to this requested model. model is a deprecated alias.
mode (query)stringoptionalRows with this mode (routes: active, observe, disabled; limits: enforce, alert, paused).
references (query)stringoptional<provider_label> or <provider_label>/<model>: rows that name it, following destination and failover-profile refs (adds references [paths]).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routing-constraints?limit=example' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/routing-constraints/{resource_id}Delete a routing constraint
Removes the routing constraint; refused while other controls reference it. If-Match is required.
routing:constraintsPath, query & header parameters 7
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
strict (query)booleanoptionalRouting constraints: routes left without candidates become a 422 instead of warnings.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Unknown fields are rejected in this object.
curl --request DELETE \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routing-constraints/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/routing-constraints/{resource_id}Read a routing constraint
One routing constraint and its ETag.
routing:readPath, query & header parameters 1
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routing-constraints/eu-pool' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/routing-constraints/{resource_id}Update a routing constraint
JSON merge patch of the routing constraint (null removes a field); the result is validated as a whole. If-Match is required. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:constraintsPath, query & header parameters 7
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
strict (query)booleanoptionalRouting constraints: routes left without candidates become a 422 instead of warnings.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Accumulates with every matching rule (console rules included); no rank.
descriptionstringoptionalmatcharray<object>optionalTag checks, ANDed; tag plus exactly one operator.
Array item specification
equalsstring | number | booleanoptionalexistsbooleanoptionalinarray<string | number | boolean>optionalArray item specification
string | number | booleannot_inarray<string | number | boolean>optionalArray item specification
string | number | booleantagstringrequiredprovider.<key> or model.<key>, e.g. provider.geo
on_check_failureobjectoptional"route""block"providersobjectoptionalExactly one of in / not_in (provider labels).
Object fields
inarray<string>optionalArray item specification
stringnot_inarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
requirearray<object>optionalCapability requirements, unioned across rules.
Array item specification
namestringrequiredA capability, e.g. context_at_least
tokensintegeroptionalscopeobjectoptionalEvery non-empty list must match (AND); empty lists do not restrict.
Object fields
app_tagsarray<string>optionalArray item specification
stringappsarray<string>optionalArray item specification
stringsmart_groupsarray<string>optionalArray item specification
stringusersarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
whenobjectoptionalObject fields
data_typesarray<string>optionalArray item specification
stringcurl --request PATCH \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routing-constraints/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"'
Authentication, errors & retry rules Try it in the playground
/controls/routing-constraints/{resource_id}Create or replace a routing constraint
Creates (201) or replaces (200) the routing constraint. Changing an existing one needs If-Match; If-None-Match: * creates only. Writes publish one policy revision. A PUT whose content equals the stored resource returns changed false and publishes nothing.
routing:constraintsPath, query & header parameters 8
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringoptionalResource ETag "r<revision>-<id>-<hash8>" from the latest read, or the collection ETag "r<revision>". Required to change or delete an existing resource (428 when missing, 412 when stale); an unrelated publish does not invalidate it.
Idempotency-Key (header)stringoptionalUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Optional on PUT, PATCH and DELETE.
If-None-Match (header)"*"optionalCreate only: 412 when the resource exists with different content.
strict (query)booleanoptionalRouting constraints: routes left without candidates become a 422 instead of warnings.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Full request body specification application/json
Accumulates with every matching rule (console rules included); no rank.
descriptionstringoptionalmatcharray<object>optionalTag checks, ANDed; tag plus exactly one operator.
Array item specification
equalsstring | number | booleanoptionalexistsbooleanoptionalinarray<string | number | boolean>optionalArray item specification
string | number | booleannot_inarray<string | number | boolean>optionalArray item specification
string | number | booleantagstringrequiredprovider.<key> or model.<key>, e.g. provider.geo
on_check_failureobjectoptional"route""block"providersobjectoptionalExactly one of in / not_in (provider labels).
Object fields
inarray<string>optionalArray item specification
stringnot_inarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
requirearray<object>optionalCapability requirements, unioned across rules.
Array item specification
namestringrequiredA capability, e.g. context_at_least
tokensintegeroptionalscopeobjectoptionalEvery non-empty list must match (AND); empty lists do not restrict.
Object fields
app_tagsarray<string>optionalArray item specification
stringappsarray<string>optionalArray item specification
stringsmart_groupsarray<string>optionalArray item specification
stringusersarray<string>optionalArray item specification
stringUnknown fields are rejected in this object.
whenobjectoptionalObject fields
data_typesarray<string>optionalArray item specification
stringcurl --request PUT \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/routing-constraints/eu-pool' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r12-eu-pool-1a2b3c4d"' \
--header 'Content-Type: application/json' \
--data '{
"description": "EU residency",
"match": [
{
"in": [
"eu"
],
"tag": "provider.geo"
}
],
"providers": {
"not_in": [
"openai-direct"
]
},
"require": [
{
"name": "context_at_least",
"tokens": 128000
}
],
"scope": {
"smart_groups": [
"eu-staff"
]
}
}'
Authentication, errors & retry rules Try it in the playground
References, batch and capacity
/controls/_batchApply a batch of control changes
Up to 100 put, patch, delete or quick operations across every control collection, published as ONE revision, all or nothing. Each op may carry if_match; a failure names op_index. Each op needs its collection's write scope.
Write (or read) scope of each collection it touchesPath, query & header parameters 5
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
strict (query)booleanoptionalRouting constraints: routes left without candidates become a 422 instead of warnings.
repin (query)objectoptionalRouting writes: drop applies the change to existing conversations too by invalidating the session pins of the affected apps (keep: new conversations only). dry_run shows the apps as impact.pins.
"keep""drop"repin_scope (query)objectoptionalWith repin=drop: tenant confirms a drop of EVERY session pin of the tenant, needed when the change is not limited to named apps (else 422 repin_scope_confirmation_required).
"apps""tenant"Idempotency-Key (header)stringrequiredUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Not needed with dry_run=true.
Full request body specification application/json
opsarray<object>requiredArray item specification
bodyobjectoptionalcollectionstringrequiredCollection path, for example routes
idstringoptionalif_matchstringoptionalif_none_match"*"optionalopstringrequiredput, patch, delete or a quick operation name
Unknown fields are rejected in this object.
Unknown fields are rejected in this object.
curl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/_batch' \
--header 'Authorization: Bearer <management-key>' \
--header 'Idempotency-Key: eu-routing-change-001' \
--header 'Content-Type: application/json' \
--data '{
"ops": [
{
"body": {
"members": [
{
"model": "gpt-4.1",
"provider_label": "azure-eu",
"weight": 70
},
{
"model": "anthropic.claude-sonnet-4",
"provider_label": "bedrock-eu",
"weight": 30
}
],
"mode": "request_count",
"type": "weighted"
},
"collection": "destinations",
"id": "eu-pool",
"op": "put"
},
{
"body": {
"mode": "observe"
},
"collection": "routes",
"id": "eu-smart",
"if_match": "\"r12-eu-smart-5e6f7a8b\"",
"op": "patch"
}
]
}'
Authentication, errors & retry rules Try it in the playground
/controls/_capacityRead policy capacity
Rules, policies and policy bytes used against the tenant caps (500 rules, 200 policies, 400,000 bytes). A write that would exceed them is a 422 policy_capacity_exceeded.
routing:readNo request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/_capacity' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/referencesList references to a provider label
Every route, destination, failover profile, failover rule, failover default, routing constraint, model access entry and limit (with limits:read) that names the provider label (or one model of it), following destination and failover-profile refs, plus console rules that name it. Use it before deleting or renaming a provider.
routing:readPath, query & header parameters 2
provider_label (query)stringrequiredProvider label.
model (query)stringoptionalOne model of the label.
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/references?provider_label=azure-eu' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
Revisions
/controls/revisionsList policy revisions
Policy revisions newest first, with who made them, the operation id, the kind of writer and the managed-controls collections each changed.
routing:readPath, query & header parameters 2
limit (query)integeroptionalPage size.
cursor (query)stringoptionalnext_cursor of the previous page.
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/revisions?limit=example' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/revisions/{revision}/resources/{collection}/{resource_id}Read a resource at a revision
One control (or console row) as it was at that revision. Needs the collection's read scope.
Write (or read) scope of each collection it touchesPath, query & header parameters 3
revision (path)stringrequiredPolicy revision number.
collection (path)stringrequiredManaged-controls collection path, for example routes, destinations or rate-limits.
resource_id (path)stringrequiredClient-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/revisions/13/resources/routes/eu-pool' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/revisions/{revision}/statusRead revision rollout
How many gateway processes that served traffic for the tenant run this revision, and which lag.
routing:readPath, query & header parameters 1
revision (path)stringrequiredPolicy revision number.
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/revisions/13/status' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/controls/revisions/{revision}:restoreRestore controls from a revision
Puts every managed-controls collection (or the named domains) back to its state at that revision in one new revision; console rules are untouched. If-Match is the collection ETag and Idempotency-Key is required. A resource that would fail validation now (for example one naming a deleted provider) refuses the restore with 409 restore_conflict listing the problems; dry_run shows them. Needs the write scope of every restored domain.
Write (or read) scope of each collection it touchesPath, query & header parameters 4
revision (path)stringrequiredPolicy revision number.
dry_run (query)booleanoptionalPreview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.
If-Match (header)stringrequiredCollection ETag "r<active revision>" from the latest read (428 when missing, 412 when stale).
Idempotency-Key (header)stringrequiredUnique per logical write. A retry with the same key and body returns the original result, including after a crash once the revision was published. Not needed with dry_run=true.
Full request body specification application/json
domainsarray<string>optionalCollections to restore (for example routes, destinations); omitted = every managed-controls collection that differs.
Array item specification
stringdry_runbooleanoptionalUnknown fields are rejected in this object.
curl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/controls/revisions/13:restore' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "r13"' \
--header 'Idempotency-Key: eu-routing-change-001' \
--header 'Content-Type: application/json' \
--data '{
"domains": [
"routes"
]
}'
Authentication, errors & retry rules Try it in the playground
Diagnostics
/failover/summaryRead the failover summary
Retries, failovers and outcomes per target over a window.
routing:readPath, query & header parameters 5
from (query)stringoptionalStart (RFC 3339 or epoch seconds); default 24 h ago. The window always ends now.
to (query)stringoptionalMust be now (or omitted): 422 time_range_not_supported for an earlier end.
app (query)stringoptionalOne app only.
window (query)stringoptionalDeprecated alias of from (a look-back window such as 24h).
app_id (query)stringoptionalDeprecated alias of app.
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/failover/summary' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/routing/effectiveExplain the effective route
Which rule routes a sample request (app, requested model, user, surface family), its destination, the failover owner and resolved failover config from the same evaluation, other matching rules it outranked (shadowed), constraints and candidates left, active mark-downs and this server's health scope, for the evaluated revision. Content checks are not evaluated; nothing is sent upstream.
routing:readPath, query & header parameters 8
app (query)stringrequiredApp name.
requested_model (query)stringoptionalModel the client asks for.
user (query)stringoptionalUser email for user and smart-group scopes.
surface (query)objectoptionalRoute surface family. anthropic_messages and realtime answer 422 surface_not_supported_for_explain. Aliases (deprecated): chat, responses, vertex, bedrock.
"chat_completion""responses""vertex_ai""bedrock_runtime""anthropic_messages""realtime"session_id (query)stringoptionalReport pin state (pins are not read by the dry run).
app_name (query)stringoptionalDeprecated alias of app.
model (query)stringoptionalDeprecated alias of requested_model.
user_email (query)stringoptionalDeprecated alias of user.
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/routing/effective?app=support-bot' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/routing/summaryRead the routing summary
Traffic per route and per routing group member over a window, with each member's share against its configured weight.
routing:readPath, query & header parameters 4
from (query)stringoptionalStart (RFC 3339 or epoch seconds); default 24 h ago.
to (query)stringoptionalEnd; default now.
app (query)stringoptionalOne app only.
app_name (query)stringoptionalDeprecated alias of app.
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/routing/summary' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/routing/target-checkCheck routing targets
Whether each provider label and model can serve each client API for an app (native, converted or cannot serve), with the connection's state.
routing:readFull request body specification application/json
app_namestringrequiredclient_apisarray<string>optionalArray item specification
stringtargetsarray<object>requiredArray item specification
modelstringoptionalprovider_labelstringoptionalcurl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/routing/target-check' \
--header 'Authorization: Bearer <management-key>' \
--header 'Content-Type: application/json' \
--data '{
"app_name": "support-bot",
"client_apis": [
"chat"
],
"targets": [
{
"model": "gpt-4.1",
"provider_label": "azure-eu"
}
]
}'
Authentication, errors & retry rules Try it in the playground
/routing/testTest routing for a sample request
Runs the routing dry run for a sample body, optionally with proposed controls ({collection: {id: resource or null}}) rendered in memory. Nothing is published, pinned or sent upstream.
routing:readFull request body specification application/json
appstringoptionalApp name (app_name is the deprecated spelling).
app_namestringoptionalbodyobjectrequiredfollow_upsarray<string>optionalArray item specification
stringheadersobjectoptionalmethod_typeobjectoptionalOlder name of surface; chat, responses, vertex and bedrock are accepted as aliases of the families.
"chat""responses""vertex""bedrock""chat_completion""anthropic_messages""vertex_ai""responses""realtime""bedrock_runtime"proposedobjectoptional{collection: {id: resource | null}}: rendered in memory into a candidate source; never published.
simulate_failuresarray<object>optionalArray item specification
objectsimulate_routeobjectoptionalsurfaceobjectoptionalRoute surface family. Aliases (deprecated): chat = chat_completion, responses = responses, vertex = vertex_ai, bedrock = bedrock_runtime.
"chat_completion""anthropic_messages""vertex_ai""responses""realtime""bedrock_runtime"userstringoptionaluser_emailstringoptionalcurl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/routing/test' \
--header 'Authorization: Bearer <management-key>' \
--header 'Content-Type: application/json' \
--data '{
"app": "support-bot",
"body": {
"messages": [
{
"content": "hi",
"role": "user"
}
],
"model": "smart"
},
"proposed": {
"routes": {
"eu-smart": {
"description": "EU staff smart alias",
"destination": {
"ref": "eu-pool"
},
"failover": {
"ref": "standard"
},
"match": {
"requested_models": [
"smart"
]
},
"mode": "active",
"rank": 120,
"scope": {
"apps": [
"support-bot"
],
"smart_groups": [
"eu-staff"
]
},
"session": {
"route_decision": "per_conversation"
},
"surface_family": "chat_completion"
}
}
},
"surface": "chat_completion"
}'
Authentication, errors & retry rules Try it in the playground
Related
- Routing and failover - what routing, pinning and failover do at runtime.
- Incidents API - take a provider out of routing during an outage without a policy change.
- Rate limits API - request and token limits, request guards and temporary raises.
- Management API - authentication, scopes, errors and retry rules.