How to See the Failover History of a Request in FreeLLMAPI: Complete Guide with API and SQL Methods
FreeLLMAPI records every hop a request makes through the failover ladder in durable storage, exposing this history via the /analytics endpoint, database queries, and optional response headers.
FreeLLMAPI implements resilient routing through an ordered failover ladder—when your primary provider fails, the system automatically tries alternatives. Understanding how to inspect this failover history helps you debug latency spikes, diagnose provider outages, and optimize your model selection strategy. This guide covers three methods to retrieve the complete attempt trace for any request.
What Gets Recorded in Failover History
Each request generates an AttemptTrace object for every provider/model tried during routing. As defined in server/src/lib/attempt-trace.ts, these traces capture:
- The provider and model attempted
- Start and end timestamps for precise latency measurement
- The outcome (success, timeout, quota-exhausted, rate-limited, etc.)
- A redacted error summary for privacy-compliant debugging
All attempts link to their parent request, forming a chronological "failover ladder" you can inspect retroactively.
Method 1: Query the Analytics API (Recommended)
The standard way to view failover history is through the /analytics/requests/:id endpoint implemented in server/src/routes/analytics.ts.
Step 1: Capture the Request ID
Every response includes the header x-request-id. Capture this in your client:
const requestId = response.headers.get('x-request-id');
console.log('Request ID:', requestId); // e.g., 'a1b2c3d4-5678-90ab-cdef-Example11'
Step 2: Fetch Failover History
const requestId = 'a1b2c3d4-5678-90ab-cdef-Example11';
const resp = await fetch(
`https://api.freellmapi.com/analytics/requests/${requestId}`,
{
headers: {
Authorization: `Bearer ${process.env.FREELLMAPI_TOKEN}`,
},
}
);
const data = await resp.json();
console.log('Failover ladder:', data.attempts);
The response contains an attempts array with the full sequence:
{
"id": "a1b2c3d4-5678-90ab-cdef-Example11",
"created_at": "2024-01-15T09:23:17Z",
"final_provider": "openrouter",
"final_model": "anthropic/claude-3-opus",
"attempts": [
{
"attempt_index": 0,
"provider": "openai",
"model": "gpt-4-turbo",
"start_ts": "2024-01-15T09:23:17.123Z",
"end_ts": "2024-01-15T09:23:19.456Z",
"outcome": "timeout",
"error_summary": "Request deadline exceeded (30s)"
},
{
"attempt_index": 1,
"provider": "openrouter",
"model": "anthropic/claude-3-opus",
"start_ts": "2024-01-15T09:23:19.789Z",
"end_ts": "2024-01-15T09:23:22.101Z",
"outcome": "success",
"error_summary": null
}
]
}
Method 2: Direct Database Query
For operational investigations or custom dashboards, query the request_attempts table directly. This schema was created by migration server/src/db/migrations/20260726_000002_request_attempts.ts.
PostgreSQL Query
SELECT
attempt_index,
provider,
model,
start_ts,
end_ts,
outcome,
error_summary
FROM request_attempts
WHERE request_id = 'a1b2c3d4-5678-90ab-cdef-Example11'
ORDER BY attempt_index;
Key columns explained:
| Column | Purpose |
|---|---|
attempt_index |
Position in failover sequence (0 = first attempt) |
outcome |
Result classification used for analytics aggregation |
error_summary |
Sanitized error message (PII-redacted) |
Method 3: Real-Time Failover Trace Headers
For immediate visibility without subsequent API calls, enable the optional trace header via server/src/lib/fallback-loop.ts.
Client-Opt-In Request
Add the X-Failover-Trace: true header:
curl -s -D - \
-H "Authorization: Bearer $FREELLMAPI_TOKEN" \
-H "X-Failover-Trace: true" \
-H "Content-Type: application/json" \
https://api.freellmapi.com/v1/chat/completions \
-d '{
"model": "gpt-4",
"messages": [{"role": "user", "content": "Hello"}]
}'
Response Header Inspection
Look for X-Fallback-Trace in the response:
HTTP/1.1 200 OK
x-request-id: a1b2c3d4-5678-90ab-cdef-Example11
x-fallback-trace: [{"idx":0,"provider":"openai","model":"gpt-4","outcome":"timeout","ms":23047},{"idx":1,"provider":"openrouter","model":"anthropic/claude-3-opus","outcome":"success","ms":2312}]
This compact JSON format is designed for low-overhead logging integration.
Understanding Failover Budget and Cooldown Data
The failover history reveals operational details beyond simple success/failure:
- Failover budget consumed: Each failed attempt deducts from your configured budget; the history shows remaining budget at each hop
- Cooldown applied: When providers hit rate limits, the
fallback-loop.tslogic inserts calculated delays—visible in timestamp gaps between attempts - Exhaustion state: If all providers fail, the final entry shows
outcome: "exhausted"with an aggregated error summary
These metrics help you tune server/src/lib/fallback-loop.ts configuration parameters like max_attempts and per_provider_timeout.
Source Code Reference Map
| File | Role in Failover History |
|---|---|
server/src/lib/attempt-trace.ts |
Defines AttemptTrace structure for per-attempt recording |
server/src/lib/request-log.ts |
Persists request row and associated attempt array |
server/src/routes/analytics.ts |
Implements /analytics/requests/:id endpoint |
server/src/lib/fallback-loop.ts |
Sets optional X-Fallback-Trace response header |
server/src/db/migrations/20260726_000002_request_attempts.ts |
Database schema for durable attempt storage |
Summary
- Capture
x-request-idfrom every response to enable later history retrieval - Use
/analytics/requests/:idfor the complete, formatted failover ladder with full metadata - Query
request_attemptstable directly for operational dashboards and bulk analysis - Enable
X-Failover-Trace: truefor real-time visibility without additional API calls - Inspect
attempt_index, timestamps, and outcomes to diagnose provider reliability and routing efficiency
Frequently Asked Questions
How long is failover history retained in FreeLLMAPI?
According to the server/src/lib/request-log.ts implementation, attempt records follow the parent request's retention policy. Typically this is 90 days for standard tiers and 365 days for enterprise plans, though you should verify your specific contract. The database migration uses standard PostgreSQL partitioning to manage time-series data efficiently.
Can I export failover history for multiple requests at once?
Yes. The analytics endpoint supports batch queries via POST /analytics/requests/batch with a JSON body containing an array of request IDs. Maximum batch size is enforced by server/src/routes/analytics.ts (typically 100 IDs). For larger exports, query the request_attempts table directly with date-range filters on start_ts.
What does "outcome" value "quota-exhausted" indicate?
This outcome from attempt-trace.ts means the provider rejected the request due to account-level limits—distinct from rate-limiting which shows as rate_limited. Quota exhaustion typically requires provider dashboard intervention or tier upgrade, while rate limits resolve after cooldown periods configured in fallback-loop.ts.
Is the X-Fallback-Trace header available on all response statuses?
No. As implemented in server/src/lib/fallback-loop.ts, the header is only attached when: (1) the client sends X-Failover-Trace: true, AND (2) the request completes the failover loop (success or exhaustion). Early client errors (400-class) that fail validation before routing will not include trace data since no provider attempts occurred.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →