Skip to main content

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.

Destinations
Weighted pool
Ordered targets
Routes
Requested model + scope
Rank, mode
Failover
Profiles, rules
Tenant default
Guard rails
Routing constraints
Model access
Verify
Revision rollout
Explain, dry-run test
QuilrAI
ResourceWhat it isRead scopeWrite scope
DestinationsA named weighted pool (weights total 100) or an ordered target list. Routes reference it by id. Quick operations: :set-weights, :replace-member.routing:readrouting:write
RoutesWhich destination serves a requested model, for which apps, smart groups, users or app tags. Quick operation: :set-mode.routing:readrouting:write
Failover profilesReusable failover settings (tier, backups, tries, retries, timeouts).routing:readrouting:write
Failover rulesFailover for a scope when the deciding route has none.routing:readrouting:write
Failover defaultOne tenant-wide failover setting; deleting it returns to the built-in default.routing:readrouting:write
Routing constraintsHard limits on where requests may go: provider tags such as provider.geo, required capabilities, allowed or excluded provider labels.routing:readrouting:constraints
Model accessAllow and deny lists of requested models for a scope.routing:readrouting:write
References, revisions, diagnosticsFind everything that uses a provider, revision history and restore, rollout status, explain a route, dry-run test.routing:readwrite scope of each restored collection

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 /capabilities reports managed_controls.enabled and which collections are available.
  • Issue a key with routing:read and routing:write (add routing:constraints for 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.

Client request
POST /openai_compatible/v1/chat/completions
{ "model": "smart", "messages": [...] }
app: support-bot   user: dana@example.com
QuilrAI LLM Gateway
Admit
Model access
Allow / deny requested models
Deny wins: 403 model_access_denied
Select route
Matching routes
Requested model + scope
Highest rank wins
Observe-mode routes only report
Destination
Weighted: share of conversations
Ordered: first usable target
Conversation pin kept
Filter
Routing constraints
Every matching constraint applies
Tags, capabilities, providers
Unknown facts exclude
Send and fail over
Same-target retry
Timeouts, 429, 5xx
Up to same_target_retries
Failover tiers
1. Rest of the route
2. Backup models (fallbacks)
3. Same model, other connections
4. Other app models
Mark-downs and cooldowns skip unhealthy targets · max_attempts counts every send
Provider models
azure-eu / gpt-4.1bedrock-eu / claude-sonnetopenai / gpt-4.1-mini
QuilrAI

A 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​

  1. Does the deciding route have its own failover?
    yes:
    Route failoverfailover_owner.kind: route
  2. Does a failover rule match the request?Highest rank first
    yes:
    Failover rulekind: failover_rule
  3. Is a failover default set?
    yes:
    Failover defaultkind: failover_default
  4. None of the above
    Built-in defaultkind: built_in_default
QuilrAI

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 rank on create and the API assigns the highest overlapping rank plus 10, returned with rank_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_family as 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, with coverage: full (this route never routes) or partial.

Worked example. One tenant, three managed rules:

RuleScopeRequested modelRank
Route eu-smartsmart group eu-staffsmart120
Route smart-defaulteveryonesmart20
Failover rule eu-staff-failoversmart group eu-staffany30
  • An eu-staff user asking for smart matches both routes: eu-smart (120) wins. /routing/effective lists smart-default under shadowed, and smart-default reads shadowed_by: [{route_id: "eu-smart", coverage: "partial"}].
  • Another eu-staff route for smart at rank 120 is 422 route_rank_conflict; omit the rank to get 130.
  • A failover rule for eu-staff at rank 120 also conflicts (shared rank space); 30 is fine.
  • If eu-smart has no failover of its own, eu-staff-failover supplies it (failover_owner.kind: failover_rule). If it has one, the route's wins (kind: route).

Writes, versions and idempotency​

Read
ETag per resource
"r<rev>-<id>-<hash>"
Dry run
?dry_run=true
diff, impact, warnings
Write
If-Match / Idempotency-Key
One validated revision
Live
Revision status
Explain the route
QuilrAI
RuleDetail
PUT is content-idempotentPUT /controls/{collection}/{id} creates (201) or replaces (200). A PUT whose content equals what is stored returns 200 with changed: false and publishes nothing, so a pipeline can apply the same file every run.
Create onlyIf-None-Match: * makes a PUT create-only: 412 when the id exists with other content.
Changing needs the ETagChanging or deleting an existing resource needs If-Match with the resource ETag (428 without, 412 when stale). The collection ETag "r<revision>" is also accepted. A publish elsewhere in the tenant does not invalidate a resource's ETag.
PATCHJSON merge patch: null removes a field. Read-only fields echoed from a read are ignored.
POST needs a keyQuick operations, _batch and restore need Idempotency-Key (400 idempotency_key_required). A retry with the same key replays the original result for 24 hours, including a no-op; the same key with another body is 409 idempotency_conflict.
Dry run?dry_run=true returns diff.spec (one {collection, id, op, before, after} per changed resource), diagnostics, warnings, impact (apps, routes, models, routes_without_candidates, pins) and capacity, and publishes nothing.
BatchPOST /controls/_batch applies up to 100 operations across collections as one revision, all or nothing. Each op is {op, collection, id, body?, if_match?, if_none_match?}; a failure names op_index.
CapacityGET /controls/_capacity shows rules, policies and policy size against the tenant caps; a write past them is 422 policy_capacity_exceeded.
Console rowsLists show console-authored rules of the same kind as read-only rows (source: "console"). Writing one is 409 rule_not_api_managed.

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​

  • mode is active, observe (evaluated and reported, never routes) or disabled (kept, not applied). enabled: false is an alias for disabled. POST /controls/routes/{id}:set-mode switches it without resending the route.
  • surface_family names the client API family: chat_completion, anthropic_messages, vertex_ai, responses, realtime or bedrock_runtime. It is required for weighted destinations. A list makes one rule per family, each matching only that API; chat_completion and anthropic_messages cannot share a list (422 surface_family_overlap).
  • session.route_decision is per_conversation (default) or per_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).

Dropping pins costs cache

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​

  1. Rollout. GET /controls/revisions/{revision}/status counts gateway processes that served the tenant in the last hour: processes_reporting, processes_on_rev, lagging, and complete (at least one reports and none lags). processes_reporting: 0 means no recent traffic, not "not applied"; an idle gateway picks the revision up on its next request.
  2. Explain. GET /routing/effective?app=&requested_model=&user=&surface= shows the route that wins, its destination, failover_owner and resolved failover, the rules it outranked (shadowed), constraints, candidates left and active mark-downs, for the evaluated revision (revision_current). Nothing is sent upstream.
  3. Test a proposal. POST /routing/test runs the routing dry run for a sample body, optionally with proposed controls ({collection: {id: resource | null}}) rendered in memory. Nothing is published, pinned or sent upstream. POST /routing/target-check says whether each provider model can serve each client API (native, converted or not at all).
  4. Watch traffic. GET /routing/summary shows traffic per route and destination member against its weight; GET /failover/summary shows 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​

StatusCodes
400invalid_request, idempotency_key_required
403insufficient_scope
404not_found, revision_not_found, app_not_found
409policy_not_enabled, managed_controls_disabled (writes turned off for the deployment; dry runs still answer), rule_not_api_managed, destination_in_use, failover_profile_in_use, idempotency_conflict, collection_changed, managed_controls_changed, policy_conflict, restore_conflict
412version_conflict
422validation_failed, route_rank_conflict, policy_capacity_exceeded, invalid_named_reference, invalid_weights, member_not_found, surface_family_required, surface_family_overlap, invalid_route_decision, too_many_resources, routing_constraint_no_candidates (with ?strict=true; otherwise a warning), repin_scope_confirmation_required, surface_not_supported_for_explain, time_range_not_supported
428precondition_required
429test_routing_busy
503central_service_required, revision_status_unavailable, test_routing_unavailable

Endpoints​

Destinations​

GET/controls/destinations

List 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.

REQUIRESrouting:read
Path, query & header parameters 7
limit (query)integeroptional

Page size.

min: 1max: 500default: 100
cursor (query)stringoptional

next_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).

source (query)objectoptional

Only managed resources or only console rows.

"managed""console"
app (query)stringoptional

Rows 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)stringoptional

Rows that can apply to this requested model. model is a deprecated alias.

mode (query)stringoptional

Rows 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

DELETE/controls/destinations/{resource_id}

Delete a destination

Removes the destination; refused while other controls reference it. If-Match is required.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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

GET/controls/destinations/{resource_id}

Read a destination

One destination and its ETag.

REQUIRESrouting:read
Path, query & header parameters 1
resource_id (path)stringrequired

Client-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

PATCH/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.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

Variant 1 object
descriptionstringoptional
membersarray<object>required
min items: 1max items: 64
Array item specification
modelstringrequired
provider_labelstringrequired
weightnumberrequired
max: 100greater than: 0

Unknown fields are rejected in this object.

modeobjectoptional
"request_count""token"
type"weighted"required
Variant 2 object
descriptionstringoptional
targetsarray<object>required
min items: 1max items: 64
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

type"ordered"required
curl --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

PUT/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.

REQUIRESrouting:write
Path, query & header parameters 7
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringoptional

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
If-None-Match (header)"*"optional

Create only: 412 when the resource exists with different content.

repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

Variant 1 object
descriptionstringoptional
membersarray<object>required
min items: 1max items: 64
Array item specification
modelstringrequired
provider_labelstringrequired
weightnumberrequired
max: 100greater than: 0

Unknown fields are rejected in this object.

modeobjectoptional
"request_count""token"
type"weighted"required
Variant 2 object
descriptionstringoptional
targetsarray<object>required
min items: 1max items: 64
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

type"ordered"required
curl --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

POST/controls/destinations/{resource_id}:replace-member

Replace 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.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringrequired

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

fromobjectrequired
Object fields
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

toobjectrequired
Object fields
modelstringrequired
provider_labelstringrequired

Unknown 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

POST/controls/destinations/{resource_id}:set-weights

Set 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.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringrequired

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

membersarray<object>required
Array item specification
modelstringrequired
provider_labelstringrequired
weightnumberrequired
max: 100greater than: 0

Unknown 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​

GET/controls/routes

List 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.

REQUIRESrouting:read
Path, query & header parameters 7
limit (query)integeroptional

Page size.

min: 1max: 500default: 100
cursor (query)stringoptional

next_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).

source (query)objectoptional

Only managed resources or only console rows.

"managed""console"
app (query)stringoptional

Rows 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)stringoptional

Rows that can apply to this requested model. model is a deprecated alias.

mode (query)stringoptional

Rows 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

DELETE/controls/routes/{resource_id}

Delete a route

Removes the route; refused while other controls reference it. If-Match is required.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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

GET/controls/routes/{resource_id}

Read a route

One route and its ETag.

REQUIRESrouting:read
Path, query & header parameters 1
resource_id (path)stringrequired

Client-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

PATCH/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.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

descriptionstringoptional
destinationone of 2 variantsrequired
Variant 1 object
refstringrequired

Unknown fields are rejected in this object.

Variant 2 one of 2 variants
Variant 1 object
descriptionstringoptional
membersarray<object>required
min items: 1max items: 64
Array item specification
modelstringrequired
provider_labelstringrequired
weightnumberrequired
max: 100greater than: 0

Unknown fields are rejected in this object.

modeobjectoptional
"request_count""token"
type"weighted"required
Variant 2 object
descriptionstringoptional
targetsarray<object>required
min items: 1max items: 64
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

type"ordered"required
enabledbooleanoptional

Alias of mode: false = disabled, true re-enables a disabled route as active. Sent together with mode, the two must agree.

failoverone of 2 variantsoptional

The route's whole failover object; omitted = the matching failover rule, else the tenant default.

Variant 1 object
refstringrequired

Unknown fields are rejected in this object.

Variant 2 object
attempt_timeout_msintegeroptional
min: 0max: 300000
candidate_scopeobjectoptional

Alias of scope (the candidate tier); returned on reads.

"route""same_model""app"
capabilitiesobjectoptional
enabledbooleanoptional
fallbacksarray<object>optional
max items: 8
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

max_attemptsintegeroptional
min: 1max: 3
onarray<object>optional
Array item specification
object

Values: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"

preferencearray<string>optional
max items: 32
Array item specification
string
same_target_retriesintegeroptional
min: 0max: 2
scopeobjectoptional

Candidate tier: how far failover may look for another target (not the resource scope).

"route""same_model""app"
total_timeout_msintegeroptional
min: 1000max: 600000

Unknown fields are rejected in this object.

matchobjectoptional
Object fields
requested_modelsarray<string>optional
max items: 64
Array item specification
string

Unknown fields are rejected in this object.

modeobjectoptional
"active""observe""disabled"
rankintegeroptional

Order 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.

min: 1max: 9999
scopeobjectoptional

Every non-empty list must match (AND); empty lists do not restrict.

Object fields
app_tagsarray<string>optional
max items: 100
Array item specification
string
min length: 1
appsarray<string>optional
max items: 100
Array item specification
string
min length: 1
smart_groupsarray<string>optional
max items: 100
Array item specification
string
min length: 1
usersarray<string>optional
max items: 100
Array item specification
string
min length: 1

Unknown fields are rejected in this object.

sessionobjectoptional
Object fields
route_decisionobjectoptional
"per_conversation""per_message"
surface_familyone of 2 variantsoptional

The 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
object

Values: "chat_completion""anthropic_messages""vertex_ai""responses""realtime""bedrock_runtime"

Variant 2 array<object>
array<object>
min items: 1unique items
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

PUT/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.

REQUIRESrouting:write
Path, query & header parameters 7
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringoptional

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
If-None-Match (header)"*"optional

Create only: 412 when the resource exists with different content.

repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

descriptionstringoptional
destinationone of 2 variantsrequired
Variant 1 object
refstringrequired

Unknown fields are rejected in this object.

Variant 2 one of 2 variants
Variant 1 object
descriptionstringoptional
membersarray<object>required
min items: 1max items: 64
Array item specification
modelstringrequired
provider_labelstringrequired
weightnumberrequired
max: 100greater than: 0

Unknown fields are rejected in this object.

modeobjectoptional
"request_count""token"
type"weighted"required
Variant 2 object
descriptionstringoptional
targetsarray<object>required
min items: 1max items: 64
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

type"ordered"required
enabledbooleanoptional

Alias of mode: false = disabled, true re-enables a disabled route as active. Sent together with mode, the two must agree.

failoverone of 2 variantsoptional

The route's whole failover object; omitted = the matching failover rule, else the tenant default.

Variant 1 object
refstringrequired

Unknown fields are rejected in this object.

Variant 2 object
attempt_timeout_msintegeroptional
min: 0max: 300000
candidate_scopeobjectoptional

Alias of scope (the candidate tier); returned on reads.

"route""same_model""app"
capabilitiesobjectoptional
enabledbooleanoptional
fallbacksarray<object>optional
max items: 8
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

max_attemptsintegeroptional
min: 1max: 3
onarray<object>optional
Array item specification
object

Values: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"

preferencearray<string>optional
max items: 32
Array item specification
string
same_target_retriesintegeroptional
min: 0max: 2
scopeobjectoptional

Candidate tier: how far failover may look for another target (not the resource scope).

"route""same_model""app"
total_timeout_msintegeroptional
min: 1000max: 600000

Unknown fields are rejected in this object.

matchobjectoptional
Object fields
requested_modelsarray<string>optional
max items: 64
Array item specification
string

Unknown fields are rejected in this object.

modeobjectoptional
"active""observe""disabled"
rankintegeroptional

Order 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.

min: 1max: 9999
scopeobjectoptional

Every non-empty list must match (AND); empty lists do not restrict.

Object fields
app_tagsarray<string>optional
max items: 100
Array item specification
string
min length: 1
appsarray<string>optional
max items: 100
Array item specification
string
min length: 1
smart_groupsarray<string>optional
max items: 100
Array item specification
string
min length: 1
usersarray<string>optional
max items: 100
Array item specification
string
min length: 1

Unknown fields are rejected in this object.

sessionobjectoptional
Object fields
route_decisionobjectoptional
"per_conversation""per_message"
surface_familyone of 2 variantsoptional

The 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
object

Values: "chat_completion""anthropic_messages""vertex_ai""responses""realtime""bedrock_runtime"

Variant 2 array<object>
array<object>
min items: 1unique items
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

POST/controls/routes/{resource_id}:set-mode

Set 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.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringrequired

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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​

DELETE/controls/failover-default

Reset the failover default

Removes it, so the built-in default applies. If-Match is required.

REQUIRESrouting:write
Path, query & header parameters 5
dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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

PUT/controls/failover-default

Create 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.

REQUIRESrouting:write
Path, query & header parameters 6
dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringoptional

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
If-None-Match (header)"*"optional

Create only: 412 when the resource exists with different content.

repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

Tenant singleton; DELETE resets to the built-in default.

descriptionstringoptional
failoverone of 2 variantsrequired
Variant 1 object
refstringrequired

Unknown fields are rejected in this object.

Variant 2 object
attempt_timeout_msintegeroptional
min: 0max: 300000
candidate_scopeobjectoptional

Alias of scope (the candidate tier); returned on reads.

"route""same_model""app"
capabilitiesobjectoptional
enabledbooleanoptional
fallbacksarray<object>optional
max items: 8
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

max_attemptsintegeroptional
min: 1max: 3
onarray<object>optional
Array item specification
object

Values: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"

preferencearray<string>optional
max items: 32
Array item specification
string
same_target_retriesintegeroptional
min: 0max: 2
scopeobjectoptional

Candidate tier: how far failover may look for another target (not the resource scope).

"route""same_model""app"
total_timeout_msintegeroptional
min: 1000max: 600000

Unknown 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

GET/controls/failover-profiles

List 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.

REQUIRESrouting:read
Path, query & header parameters 7
limit (query)integeroptional

Page size.

min: 1max: 500default: 100
cursor (query)stringoptional

next_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).

source (query)objectoptional

Only managed resources or only console rows.

"managed""console"
app (query)stringoptional

Rows 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)stringoptional

Rows that can apply to this requested model. model is a deprecated alias.

mode (query)stringoptional

Rows 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

DELETE/controls/failover-profiles/{resource_id}

Delete a failover profile

Removes the failover profile; refused while other controls reference it. If-Match is required.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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

GET/controls/failover-profiles/{resource_id}

Read a failover profile

One failover profile and its ETag.

REQUIRESrouting:read
Path, query & header parameters 1
resource_id (path)stringrequired

Client-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

PATCH/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.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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_msintegeroptional
min: 0max: 300000
candidate_scopeobjectoptional

Alias of scope (the candidate tier); returned on reads.

"route""same_model""app"
capabilitiesobjectoptional
descriptionstringoptional
enabledbooleanoptional
fallbacksarray<object>optional
max items: 8
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

max_attemptsintegeroptional
min: 1max: 3
onarray<object>optional
Array item specification
object

Values: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"

preferencearray<string>optional
max items: 32
Array item specification
string
same_target_retriesintegeroptional
min: 0max: 2
scopeobjectoptional

Candidate tier: how far failover may look for another target (not the resource scope).

"route""same_model""app"
total_timeout_msintegeroptional
min: 1000max: 600000

Unknown 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

PUT/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.

REQUIRESrouting:write
Path, query & header parameters 7
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringoptional

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
If-None-Match (header)"*"optional

Create only: 412 when the resource exists with different content.

repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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_msintegeroptional
min: 0max: 300000
candidate_scopeobjectoptional

Alias of scope (the candidate tier); returned on reads.

"route""same_model""app"
capabilitiesobjectoptional
descriptionstringoptional
enabledbooleanoptional
fallbacksarray<object>optional
max items: 8
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

max_attemptsintegeroptional
min: 1max: 3
onarray<object>optional
Array item specification
object

Values: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"

preferencearray<string>optional
max items: 32
Array item specification
string
same_target_retriesintegeroptional
min: 0max: 2
scopeobjectoptional

Candidate tier: how far failover may look for another target (not the resource scope).

"route""same_model""app"
total_timeout_msintegeroptional
min: 1000max: 600000

Unknown 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

GET/controls/failover-rules

List 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.

REQUIRESrouting:read
Path, query & header parameters 7
limit (query)integeroptional

Page size.

min: 1max: 500default: 100
cursor (query)stringoptional

next_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).

source (query)objectoptional

Only managed resources or only console rows.

"managed""console"
app (query)stringoptional

Rows 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)stringoptional

Rows that can apply to this requested model. model is a deprecated alias.

mode (query)stringoptional

Rows 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

DELETE/controls/failover-rules/{resource_id}

Delete a failover rule

Removes the failover rule; refused while other controls reference it. If-Match is required.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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

GET/controls/failover-rules/{resource_id}

Read a failover rule

One failover rule and its ETag.

REQUIRESrouting:read
Path, query & header parameters 1
resource_id (path)stringrequired

Client-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

PATCH/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.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

descriptionstringoptional
enabledbooleanoptional
failoverone of 2 variantsrequired
Variant 1 object
refstringrequired

Unknown fields are rejected in this object.

Variant 2 object
attempt_timeout_msintegeroptional
min: 0max: 300000
candidate_scopeobjectoptional

Alias of scope (the candidate tier); returned on reads.

"route""same_model""app"
capabilitiesobjectoptional
enabledbooleanoptional
fallbacksarray<object>optional
max items: 8
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

max_attemptsintegeroptional
min: 1max: 3
onarray<object>optional
Array item specification
object

Values: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"

preferencearray<string>optional
max items: 32
Array item specification
string
same_target_retriesintegeroptional
min: 0max: 2
scopeobjectoptional

Candidate tier: how far failover may look for another target (not the resource scope).

"route""same_model""app"
total_timeout_msintegeroptional
min: 1000max: 600000

Unknown fields are rejected in this object.

matchobjectoptional
Object fields
requested_modelsarray<string>optional
max items: 64
Array item specification
string

Unknown fields are rejected in this object.

rankintegeroptional

Order 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.

min: 1max: 9999
scopeobjectoptional

Every non-empty list must match (AND); empty lists do not restrict.

Object fields
app_tagsarray<string>optional
max items: 100
Array item specification
string
min length: 1
appsarray<string>optional
max items: 100
Array item specification
string
min length: 1
smart_groupsarray<string>optional
max items: 100
Array item specification
string
min length: 1
usersarray<string>optional
max items: 100
Array item specification
string
min length: 1

Unknown 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

PUT/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.

REQUIRESrouting:write
Path, query & header parameters 7
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringoptional

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
If-None-Match (header)"*"optional

Create only: 412 when the resource exists with different content.

repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

descriptionstringoptional
enabledbooleanoptional
failoverone of 2 variantsrequired
Variant 1 object
refstringrequired

Unknown fields are rejected in this object.

Variant 2 object
attempt_timeout_msintegeroptional
min: 0max: 300000
candidate_scopeobjectoptional

Alias of scope (the candidate tier); returned on reads.

"route""same_model""app"
capabilitiesobjectoptional
enabledbooleanoptional
fallbacksarray<object>optional
max items: 8
Array item specification
modelstringrequired
provider_labelstringrequired

Unknown fields are rejected in this object.

max_attemptsintegeroptional
min: 1max: 3
onarray<object>optional
Array item specification
object

Values: "timeout""connection""rate_limit""server_error""auth""model_not_found""context_length""content_filter"

preferencearray<string>optional
max items: 32
Array item specification
string
same_target_retriesintegeroptional
min: 0max: 2
scopeobjectoptional

Candidate tier: how far failover may look for another target (not the resource scope).

"route""same_model""app"
total_timeout_msintegeroptional
min: 1000max: 600000

Unknown fields are rejected in this object.

matchobjectoptional
Object fields
requested_modelsarray<string>optional
max items: 64
Array item specification
string

Unknown fields are rejected in this object.

rankintegeroptional

Order 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.

min: 1max: 9999
scopeobjectoptional

Every non-empty list must match (AND); empty lists do not restrict.

Object fields
app_tagsarray<string>optional
max items: 100
Array item specification
string
min length: 1
appsarray<string>optional
max items: 100
Array item specification
string
min length: 1
smart_groupsarray<string>optional
max items: 100
Array item specification
string
min length: 1
usersarray<string>optional
max items: 100
Array item specification
string
min length: 1

Unknown 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​

GET/controls/model-access

List 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.

REQUIRESrouting:read
Path, query & header parameters 7
limit (query)integeroptional

Page size.

min: 1max: 500default: 100
cursor (query)stringoptional

next_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).

source (query)objectoptional

Only managed resources or only console rows.

"managed""console"
app (query)stringoptional

Rows 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)stringoptional

Rows that can apply to this requested model. model is a deprecated alias.

mode (query)stringoptional

Rows 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

DELETE/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.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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

GET/controls/model-access/{resource_id}

Read a model access rule

One model access rule and its ETag.

REQUIRESrouting:read
Path, query & header parameters 1
resource_id (path)stringrequired

Client-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

PATCH/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.

REQUIRESrouting:write
Path, query & header parameters 6
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

allowarray<string>optional
Array item specification
string
denyarray<string>optional
Array item specification
string
descriptionstringoptional
scopeobjectoptional

Every non-empty list must match (AND); empty lists do not restrict.

Object fields
app_tagsarray<string>optional
max items: 100
Array item specification
string
min length: 1
appsarray<string>optional
max items: 100
Array item specification
string
min length: 1
smart_groupsarray<string>optional
max items: 100
Array item specification
string
min length: 1
usersarray<string>optional
max items: 100
Array item specification
string
min length: 1

Unknown 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

PUT/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.

REQUIRESrouting:write
Path, query & header parameters 7
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringoptional

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
If-None-Match (header)"*"optional

Create only: 412 when the resource exists with different content.

repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

allowarray<string>optional
Array item specification
string
denyarray<string>optional
Array item specification
string
descriptionstringoptional
scopeobjectoptional

Every non-empty list must match (AND); empty lists do not restrict.

Object fields
app_tagsarray<string>optional
max items: 100
Array item specification
string
min length: 1
appsarray<string>optional
max items: 100
Array item specification
string
min length: 1
smart_groupsarray<string>optional
max items: 100
Array item specification
string
min length: 1
usersarray<string>optional
max items: 100
Array item specification
string
min length: 1

Unknown 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

GET/controls/routing-constraints

List 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.

REQUIRESrouting:read
Path, query & header parameters 7
limit (query)integeroptional

Page size.

min: 1max: 500default: 100
cursor (query)stringoptional

next_cursor of the previous page; bound to the revision (409 collection_changed when the policy changed).

source (query)objectoptional

Only managed resources or only console rows.

"managed""console"
app (query)stringoptional

Rows 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)stringoptional

Rows that can apply to this requested model. model is a deprecated alias.

mode (query)stringoptional

Rows 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

DELETE/controls/routing-constraints/{resource_id}

Delete a routing constraint

Removes the routing constraint; refused while other controls reference it. If-Match is required.

REQUIRESrouting:constraints
Path, query & header parameters 7
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
strict (query)booleanoptional

Routing constraints: routes left without candidates become a 422 instead of warnings.

default: false
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"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

GET/controls/routing-constraints/{resource_id}

Read a routing constraint

One routing constraint and its ETag.

REQUIRESrouting:read
Path, query & header parameters 1
resource_id (path)stringrequired

Client-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

PATCH/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.

REQUIRESrouting:constraints
Path, query & header parameters 7
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
strict (query)booleanoptional

Routing constraints: routes left without candidates become a 422 instead of warnings.

default: false
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

Accumulates with every matching rule (console rules included); no rank.

descriptionstringoptional
matcharray<object>optional

Tag checks, ANDed; tag plus exactly one operator.

min items: 1
Array item specification
equalsstring | number | booleanoptional
existsbooleanoptional
inarray<string | number | boolean>optional
Array item specification
string | number | boolean
not_inarray<string | number | boolean>optional
Array item specification
string | number | boolean
tagstringrequired

provider.<key> or model.<key>, e.g. provider.geo

pattern: ^(provider|model)\.[^ ]{1,64}$
on_check_failureobjectoptional
"route""block"
providersobjectoptional

Exactly one of in / not_in (provider labels).

min fields: 1
Object fields
inarray<string>optional
Array item specification
string
not_inarray<string>optional
Array item specification
string

Unknown fields are rejected in this object.

requirearray<object>optional

Capability requirements, unioned across rules.

min items: 1
Array item specification
namestringrequired

A capability, e.g. context_at_least

tokensintegeroptional
min: 1
scopeobjectoptional

Every non-empty list must match (AND); empty lists do not restrict.

Object fields
app_tagsarray<string>optional
max items: 100
Array item specification
string
min length: 1
appsarray<string>optional
max items: 100
Array item specification
string
min length: 1
smart_groupsarray<string>optional
max items: 100
Array item specification
string
min length: 1
usersarray<string>optional
max items: 100
Array item specification
string
min length: 1

Unknown fields are rejected in this object.

whenobjectoptional
Object fields
data_typesarray<string>optional
Array item specification
string
curl --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

PUT/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.

REQUIRESrouting:constraints
Path, query & header parameters 8
resource_id (path)stringrequired

Client-chosen control ID, ^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$ (console rules read as console:<policy>:<rule_index>).

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringoptional

Resource 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)stringoptional

Unique 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.

min length: 1max length: 200
If-None-Match (header)"*"optional

Create only: 412 when the resource exists with different content.

strict (query)booleanoptional

Routing constraints: routes left without candidates become a 422 instead of warnings.

default: false
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Full request body specification application/json

Accumulates with every matching rule (console rules included); no rank.

descriptionstringoptional
matcharray<object>optional

Tag checks, ANDed; tag plus exactly one operator.

min items: 1
Array item specification
equalsstring | number | booleanoptional
existsbooleanoptional
inarray<string | number | boolean>optional
Array item specification
string | number | boolean
not_inarray<string | number | boolean>optional
Array item specification
string | number | boolean
tagstringrequired

provider.<key> or model.<key>, e.g. provider.geo

pattern: ^(provider|model)\.[^ ]{1,64}$
on_check_failureobjectoptional
"route""block"
providersobjectoptional

Exactly one of in / not_in (provider labels).

min fields: 1
Object fields
inarray<string>optional
Array item specification
string
not_inarray<string>optional
Array item specification
string

Unknown fields are rejected in this object.

requirearray<object>optional

Capability requirements, unioned across rules.

min items: 1
Array item specification
namestringrequired

A capability, e.g. context_at_least

tokensintegeroptional
min: 1
scopeobjectoptional

Every non-empty list must match (AND); empty lists do not restrict.

Object fields
app_tagsarray<string>optional
max items: 100
Array item specification
string
min length: 1
appsarray<string>optional
max items: 100
Array item specification
string
min length: 1
smart_groupsarray<string>optional
max items: 100
Array item specification
string
min length: 1
usersarray<string>optional
max items: 100
Array item specification
string
min length: 1

Unknown fields are rejected in this object.

whenobjectoptional
Object fields
data_typesarray<string>optional
Array item specification
string
curl --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​

POST/controls/_batch

Apply 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.

REQUIRESWrite (or read) scope of each collection it touches
Path, query & header parameters 5
dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
strict (query)booleanoptional

Routing constraints: routes left without candidates become a 422 instead of warnings.

default: false
repin (query)objectoptional

Routing 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.

default: "keep"
"keep""drop"
repin_scope (query)objectoptional

With 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).

default: "apps"
"apps""tenant"
Idempotency-Key (header)stringrequired

Unique 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.

min length: 1max length: 200
Full request body specification application/json

opsarray<object>required
min items: 1max items: 100
Array item specification
bodyobjectoptional
collectionstringrequired

Collection path, for example routes

idstringoptional
if_matchstringoptional
if_none_match"*"optional
opstringrequired

put, 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

GET/controls/_capacity

Read 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.

REQUIRESrouting:read

No 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

GET/controls/references

List 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.

REQUIRESrouting:read
Path, query & header parameters 2
provider_label (query)stringrequired

Provider label.

model (query)stringoptional

One 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​

GET/controls/revisions

List policy revisions

Policy revisions newest first, with who made them, the operation id, the kind of writer and the managed-controls collections each changed.

REQUIRESrouting:read
Path, query & header parameters 2
limit (query)integeroptional

Page size.

min: 1max: 200default: 50
cursor (query)stringoptional

next_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

GET/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.

REQUIRESWrite (or read) scope of each collection it touches
Path, query & header parameters 3
revision (path)stringrequired

Policy revision number.

collection (path)stringrequired

Managed-controls collection path, for example routes, destinations or rate-limits.

resource_id (path)stringrequired

Client-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

GET/controls/revisions/{revision}/status

Read revision rollout

How many gateway processes that served traffic for the tenant run this revision, and which lag.

REQUIRESrouting:read
Path, query & header parameters 1
revision (path)stringrequired

Policy 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

POST/controls/revisions/{revision}:restore

Restore 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.

REQUIRESWrite (or read) scope of each collection it touches
Path, query & header parameters 4
revision (path)stringrequired

Policy revision number.

dry_run (query)booleanoptional

Preview: spec and policy diff, diagnostics, warnings, would_publish and impact; nothing is saved.

default: false
If-Match (header)stringrequired

Collection ETag "r<active revision>" from the latest read (428 when missing, 412 when stale).

Idempotency-Key (header)stringrequired

Unique 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.

min length: 1max length: 200
Full request body specification application/json

domainsarray<string>optional

Collections to restore (for example routes, destinations); omitted = every managed-controls collection that differs.

min items: 1
Array item specification
string
dry_runbooleanoptional
default: false

Unknown 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​

GET/failover/summary

Read the failover summary

Retries, failovers and outcomes per target over a window.

REQUIRESrouting:read
Path, query & header parameters 5
from (query)stringoptional

Start (RFC 3339 or epoch seconds); default 24 h ago. The window always ends now.

to (query)stringoptional

Must be now (or omitted): 422 time_range_not_supported for an earlier end.

app (query)stringoptional

One app only.

window (query)stringoptional

Deprecated alias of from (a look-back window such as 24h).

app_id (query)stringoptional

Deprecated 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

GET/routing/effective

Explain 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.

REQUIRESrouting:read
Path, query & header parameters 8
app (query)stringrequired

App name.

requested_model (query)stringoptional

Model the client asks for.

user (query)stringoptional

User email for user and smart-group scopes.

surface (query)objectoptional

Route surface family. anthropic_messages and realtime answer 422 surface_not_supported_for_explain. Aliases (deprecated): chat, responses, vertex, bedrock.

default: "chat_completion"
"chat_completion""responses""vertex_ai""bedrock_runtime""anthropic_messages""realtime"
session_id (query)stringoptional

Report pin state (pins are not read by the dry run).

app_name (query)stringoptional

Deprecated alias of app.

model (query)stringoptional

Deprecated alias of requested_model.

user_email (query)stringoptional

Deprecated 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

GET/routing/summary

Read the routing summary

Traffic per route and per routing group member over a window, with each member's share against its configured weight.

REQUIRESrouting:read
Path, query & header parameters 4
from (query)stringoptional

Start (RFC 3339 or epoch seconds); default 24 h ago.

to (query)stringoptional

End; default now.

app (query)stringoptional

One app only.

app_name (query)stringoptional

Deprecated 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

POST/routing/target-check

Check 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.

REQUIRESrouting:read
Full request body specification application/json

app_namestringrequired
client_apisarray<string>optional
Array item specification
string
targetsarray<object>required
max items: 200
Array item specification
modelstringoptional
provider_labelstringoptional
curl --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

POST/routing/test

Test 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.

REQUIRESrouting:read
Full request body specification application/json

appstringoptional

App name (app_name is the deprecated spelling).

app_namestringoptional
bodyobjectrequired
follow_upsarray<string>optional
Array item specification
string
headersobjectoptional
method_typeobjectoptional

Older 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>optional
Array item specification
object
simulate_routeobjectoptional
surfaceobjectoptional

Route 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"
userstringoptional
user_emailstringoptional
curl --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