Monitoring API
Read-only views of how the gateway is behaving: what the guardrails did, how each provider and model is doing, and why one request behaved the way it did. None of them returns prompt or response text, detected values or original provider error messages.
Try all three in the Management API playground.
Which call to use
- Is it about one request?A user reports a block, an error or a slow answeryes:Explain a requestGET /requests/{id}/explain
- Is it about what the guardrails caught?Top categories, blocks per app, redactions per weekyes:Guardrail activityGET /guardrails/summary
- Is it about a provider or model?Error spikes, latency, cooldowns, mark-downsyes:Provider healthGET /provider-health
- Is it about spend, tokens or request volume?By app, user, model, key or periodyes:Usage APIGET /usage
- None of the aboveEvery request log line: Log Export API
The explain call is for single requests. To pull request logs in bulk into your data platform or SIEM, use the Log Export API.
Debug a request
Every gateway response carries an x-quilr-request-id header. Log it in your client, or ask the user who saw the problem for it.
export API="$MANAGEMENT_URL/llmgateway/management/v1"
auth=(-H "Authorization: Bearer $MANAGEMENT_KEY")
# 1. Capture the id from any gateway call
curl -si "$GATEWAY_URL/openai_compatible/v1/chat/completions" -H "Authorization: Bearer $QUILR_KEY" \
-H 'Content-Type: application/json' -d '{"model": "gpt-4.1", "messages": [{"role": "user", "content": "hi"}]}' \
| grep -i '^x-quilr-request-id'
# 2. Explain it (a short time after it completes)
curl -s "$API/requests/6f1c2a9e-1b2c-4d3e-8f90-1234567890ab/explain" "${auth[@]}" \
| jq '{summary, routing: .routing.source, failover: .failover.attempts, guardrails: .guardrails.outcome, error}'
Explain a request
request_id is the value of the x-quilr-request-id response header; provider response ids are not accepted. The last 30 days are searched. For an older request, pass timestamp (RFC 3339 or epoch seconds, any time within a day of the request). An explanation is available a short time after the request completes; until then, and for an id that does not belong to your organization, the answer is 404 request_not_found. gateway_request_id in the answer is the explained request; the top-level request_id identifies the management call itself. 503 query_timeout means the lookup exceeded its time or read limits (retry, or pass timestamp), and 503 data_unavailable means request data cannot be read right now.
Values you will see in the sections:
summary.surface: the API family, such aschat_completions(/v1/chat/completions),completions,openai_responses,anthropic_messages,embeddingsorrealtime.routing.upstream.mode:native,endpoint_switch,adapter,translateorunsupported.routing.session.key_source:previous_response_id,conversation_id,client_session_id,prompt_cache_keyorconversation_prefix.- Attempt
outcome:served,retry,failover,final_error,skipped,cancelled, or a same-target follow-up send (adaptation,format_retry,agent_check_retry). Attemptkind:response,stream,cache_hit,adaptation,format_retryoragent_check_retry. failure_class(on attempts and onerror):rate_limited,timeout_or_connection,upstream_5xx,auth_or_permission,client_4xxorother.
Sections that do not apply, or that the gateway did not record for this request, are omitted. A rule with managed: true belongs to a control managed through this API or the console (routes, limits, budgets) rather than a policy you wrote.
Guardrail activity
GET /guardrails/summary counts what the guardrails did to your traffic. Only counts and identifiers are returned.
- Counts.
requests_flaggedcounts requests with at least one detection the guardrails acted on;requests_blocked,requests_redacted(masked or partially masked) andrequests_monitored(allowed and recorded, including advisory notes) split it by action.detectionscounts each distinct category, action and direction on a request once. On rows grouped bycategory,actionordirection, one request with two matching categories counts in both rows, so do not addrequests_flaggedacross those rows: for flagged requests per period, run the same query without those dimensions (group_byempty orapp,user,model), or chartdetections. - Scanned.
requests_scannedcounts every scanned request in the app, user, model and time scope. Category, action and direction filters do not narrow it, and it isnullon rows grouped by category, action or direction. - Categories. Each category is
{id, name, type}: the id and display name from app settings and policies, or a custom definition's id and name. A redaction type such asEMAILcomes back as{"id": "EMAIL", "name": "Email Address", "type": "data_risk"}. - Not counted. Requests refused by rate limits, quotas or access rules before they were scanned, the background cache-refresh requests, and requests of apps with guardrails off.
- Totals and pages.
totalsalways covers the whole selection. Rows are ordered by period, then group keys. A cursor stops working (409) when the result changes between pages; start again from the first page.truncated: truemeans more than 5,000 rows matched. - Freshness and cost. Results can be up to 60 seconds old, and recent requests appear within a few minutes.
generated_atis when the data was read anddata_throughthe effective end of the range (yourto, or the time of the read). A summary that exceeds its 20-second time or read limits returns503 query_timeout; narrow the range or add filters and retry.503 data_unavailablemeans the data cannot be read right now.
# Blocks and redactions per category, last 30 days, for one app
FROM=$(date -u -d '30 days ago' +%F 2>/dev/null || date -u -v-30d +%F)
curl -s "$API/guardrails/summary?from=$FROM&group_by=category,action&app=Support%20Bot" "${auth[@]}" \
| jq -r '.rows[] | [.category.name, .action, .requests_flagged] | @tsv'
Provider health
GET /provider-health reports, per provider label and model, traffic outcomes over a window and how routing treats each target right now.
- Excluded traffic. Guardrail blocks, limit rejections and background cache-refresh requests are not provider traffic.
- Configured providers without traffic are listed with zero requests;
configured: falsemarks a label seen only in traffic (renamed or deleted since). - Routing state is per server. Cooldowns and circuit state are what routing on the server you called sees now, and every gateway server keeps its own (
routing_state_scope). Admin mark-downs apply on every server. State is read through each app's routing preview (at most 25 apps within 5 seconds):routing_state_scopereportsapps_total,apps_attempted,apps_evaluated(read) andapps_failed, andcompleteistrueonly when every app was read. When it isfalse, a target without a state read showsunknown, neverhealthy. - Results can be up to 60 seconds old;
generated_atis when the traffic outcomes were read.truncated: truemeans more than 500 provider and model pairs had traffic; the busiest are returned. - Errors. Queries are limited to 20 seconds:
503 query_timeoutmeans the query exceeded its time or read limits (narrow it and retry), and503 data_unavailablemeans the data cannot be read right now.
For failover totals and recovery, see Read failover summary. To take a target out of rotation, use the Incidents API.
Endpoints
/guardrails/summarySummarize guardrail activity
Counts what the gateway guardrails did to the tenant's traffic: requests scanned, flagged, blocked, redacted and monitored, and the detections behind them. Group by up to two of `category`, `action`, `direction`, `app`, `user` and `model`, and bucket by `granularity`: total (the default), or UTC `month`, `week` (starting Monday) or `day`. `from` is inclusive and `to` exclusive; a date `to` includes that whole UTC day. Only counts and identifiers are returned, never prompt or response text or the detected values. Categories are `{id, name, type}`: the ids and display names from app settings and policies; custom definitions use their id and the name you gave them. Actions are `blocked`, `redacted` (masked or partially masked) and `monitored` (allowed and recorded, including advisory notes). Requests refused by rate limits, quotas or access rules before they were scanned are not counted, and neither are the background cache-refresh requests or requests from apps with guardrails off. `totals` always covers the whole selection, whatever the page. With a category, action or direction filter, the flagged, blocked, redacted, monitored and detection counts include only matching detections, while `requests_scanned` still counts every scanned request in scope. Rows grouped by `category`, `action` or `direction` count detections, so their `requests_scanned` is null (as in the example, grouped by category and action); `totals.requests_scanned` is always set. Results can be up to 60 seconds old. Recent requests appear within a few minutes. Pages are ordered by period and then group keys; a cursor stops working (409) when the set of rows changes between pages. At most 5000 rows are returned (`truncated`). Queries are limited to 20 seconds. 503 `query_timeout` when the query exceeds its time or read limits (narrow it and retry); 503 `data_unavailable` when the data cannot be read right now.
readPath, query & header parameters 12
from (query)stringoptionalInclusive start: a date (YYYY-MM-DD, UTC midnight) or an RFC 3339 timestamp with a timezone. Omitted: all available history.
to (query)stringoptionalExclusive end: an RFC 3339 timestamp with a timezone, or a date (YYYY-MM-DD) to include that whole UTC day. Omitted: now.
granularity (query)stringoptionalPeriod of each row: total (one row per group), or UTC month, week (starting Monday) or day.
"total""month""week""day"group_by (query)array<string>optionalUp to 2 of: category, action, direction, app, user, model. Repeat the parameter (group_by=a&group_by=b) or separate values with commas (group_by=a,b).
Array item specification
stringValues: "category""action""direction""app""user""model"
app (query)stringoptionalOnly this app (exact name, case-insensitive).
user (query)stringoptionalOnly this user email (case-insensitive).
model (query)stringoptionalOnly this served model (exact).
category (query)stringoptionalOnly detections of this category: its id or display name (case-insensitive), a custom definition's id or name, or `unattributed`.
action (query)stringoptionalOnly detections handled with this action.
"blocked""redacted""monitored"direction (query)stringoptionalOnly detections in requests (prompts) or responses.
"request""response"limit (query)integeroptionalPage size: 1 to 200, default 50.
cursor (query)stringoptionalnext_cursor from the previous page; send the same other parameters.
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/guardrails/summary?limit=50' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/provider-healthRead provider health
Health of your providers and models: traffic outcomes over a window and how routing treats each target right now. Per provider label and model: served requests, success rate, errors by class (rate_limited, timeout_or_connection, upstream_5xx, auth_or_permission, client_4xx, other; the same classes request explanations report), upstream latency and time to first token (p50, p95), and how often a failed attempt moved a request to another target. Guardrail blocks, limit rejections and background cache-refresh requests are not provider traffic and are excluded. Choose window (1h, 24h, 7d, 30d; default 24h, ending now) or from and to (`from` inclusive, `to` exclusive; a date `to` includes that whole UTC day; at most 30 days, starting within the last year); filter by provider label, model or app. routing_state combines admin mark-downs with the cooldown and circuit-breaker state routing on this server sees (routing_state_scope); when some apps' state cannot be read (routing_state_scope.complete false), targets without a state report `unknown`, never healthy. `generated_at` says when the traffic outcomes were read. Configured providers without traffic are listed with zero requests. At most 500 provider and model pairs are returned (`truncated`). Results can be up to 60 seconds old. For failover totals and recovery see GET /failover/summary; to take a target out of rotation see the Incidents operations. Queries are limited to 20 seconds. 503 `query_timeout` when the query exceeds its time or read limits (narrow it and retry); 503 `data_unavailable` when the data cannot be read right now.
readPath, query & header parameters 6
window (query)stringoptionalWindow ending now. Not combined with from/to.
"1h""24h""7d""30d"from (query)stringoptionalInclusive start: a date (YYYY-MM-DD, UTC midnight) or an RFC 3339 timestamp with a timezone. Omitted: the start of window. Not combined with window; with to, at most 30 days.
to (query)stringoptionalExclusive end: an RFC 3339 timestamp with a timezone, or a date (YYYY-MM-DD) to include that whole UTC day. Omitted: now.
provider (query)stringoptionalExact provider label.
model (query)stringoptionalExact model id.
app (query)stringoptionalOnly this app's traffic, routing state and mark-downs (case-insensitive name).
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/provider-health' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
/requests/{request_id}/explainExplain a request
Why one gateway request of your tenant behaved the way it did, without prompt or response content: a summary (app, user, models, provider, status, outcome, latency, tokens, cost, response cache), how the target was chosen (route source and rule with its public route id, content-routing verdicts, routing constraints, conversation pinning, upstream API mode), every failover attempt, guardrail categories and actions per direction with the rules that decided them, limit and budget outcomes with the charged amounts, and the error code with whether a friendly error message replaced it. Detected values, message text and original provider error messages are never returned. Sections that do not apply, or that the gateway did not record for this request, are omitted. Actions use the guardrail summary's `blocked`, `redacted` and `monitored` with the same category objects, and failure classes match GET /provider-health. `gateway_request_id` is the explained request; the top-level `request_id` identifies this management call. `request_id` is the value of the `x-quilr-request-id` response header. Provider response ids are not accepted. Requests are searched in the last 30 days; for an older request pass `timestamp` (any time within a day of the request). Explanations are available a short time after the request completes. 404 `request_not_found` when no request with this id exists in your tenant within the searched window. 503 `query_timeout` when the query exceeds its time or read limits (narrow it and retry); 503 `data_unavailable` when the data cannot be read right now.
readPath, query & header parameters 2
request_id (path)stringrequiredThe gateway request id returned in the x-quilr-request-id response header.
timestamp (query)stringoptionalApproximate request time (RFC 3339 with a timezone, or epoch seconds). The search covers one day either side of it instead of the last 30 days.
No request body.
curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/requests/6f1c2a9e-1b2c-4d3e-8f90-1234567890ab/explain' \
--header 'Authorization: Bearer <management-key>'
Authentication, errors & retry rules Try it in the playground
Related
- Usage API - requests, tokens and cost by any dimension.
- Incidents API - mark a provider down during an outage.
- Routing and failover API - routes, failover and routing diagnostics.
- Log Export API - every request log line, for your own data platform.
- Management API - authentication, errors and retry rules.