What Information Is Available in the X-Routed-Via Header?

The X-Routed-Via response header reveals which provider platform and model actually processed a request, formatted as <platform>/<model> (e.g., groq/llama-3.3-70b-versatile), or returns cache when served from cache.

The X-Routed-Via header is a custom HTTP response header exposed by the FreeLLMAPI open-source project (tashfeenahmed/freellmapi) that provides transparency into request routing. When you send a request through this unified API gateway—especially with model auto-selection enabled—this header tells you exactly where your inference workload landed.

Header Format and Value Construction

The X-Routed-Via value follows a strict platform/model pattern constructed from the actual provider that served the request.

Platform and Model Identification

The value is assembled as:


<provider-platform>/<model-identifier>

For example: groq/llama-3.3-70b-versatile or openai/gpt-4o-mini.

This formatting is implemented in the response handlers across the codebase. In server/src/routes/responses.ts at line 28, the header is attached once the first meaningful output is ready to stream:

// From responses.ts - header set before streaming begins
res.setHeader('X-Routed-Via', routedViaValue(provider, model));

Similarly, server/src/routes/proxy.ts at line 23 handles this for generic proxy endpoints.

ASCII Sanitization and Percent-Encoding

Before placement in the HTTP header, the platform/model string undergoes mandatory sanitization to ensure HTTP header safety.

The routedViaValue function in server/src/lib/header-value.ts (line 52) processes the string through safeHeaderValue:

// header-value.ts - sanitization implementation
export function routedViaValue(platform: string, model: string): string {
  const raw = `${platform}/${model}`;
  return safeHeaderValue(raw); // Percent-encodes non-ASCII characters
}

Any non-ASCII characters in the platform or model name are percent-encoded to maintain header validity. For example, a model name containing Chinese characters would be encoded as %E6%88%91%E7%9A%84%E6%A8%A1%E5%9E%8B.

Cache Responses: A Special Case

When a request is served from the internal cache, the X-Routed-Via header returns a literal string rather than a provider identifier.

In server/src/routes/proxy.ts at line 75, cache hits trigger:

// proxy.ts - cache hit handling
res.setHeader('X-Routed-Via', 'cache');

This distinguishes cached responses from live inference calls, helping with debugging and cost attribution.

Reading the Header: Practical Examples

cURL Command

curl http://localhost:3001/v1/chat/completions \
  -H "Authorization: Bearer <your-unified-key>" \
  -H "Content-Type: application/json" \
  -d '{"model":"auto","messages":[{"role":"user","content":"Hello"}]}' \
  -i | grep X-Routed-Via

Sample output:


X-Routed-Via: groq/llama-3.3-70b-versatile

Fetch API (JavaScript/TypeScript)

fetch('http://localhost:3001/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${UNIFIED_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'auto',
    messages: [{ role: 'user', content: 'Hello' }]
  })
})
.then(res => {
  const routedVia = res.headers.get('X-Routed-Via');
  console.log('Routed via:', routedVia); // "groq/llama-3.3-70b-versatile"
  return res.json();
});

Decoding Percent-Encoded Values

If your provider or model names contain unicode characters, decode them with:

const routedVia = 'groq/%E6%88%91%E7%9A%84%E6%A8%A1%E5%9E%8B';
const decoded = decodeURIComponent(routedVia);
console.log(decoded); // "groq/我的模型"

Timing: When the Header Appears

The X-Routed-Via header is added once the first meaningful output is about to be streamed. This timing is deliberate—it ensures the actual serving provider is known before any response body reaches the client.

  • For streaming chat completions: Set in responses.ts before the SSE stream begins
  • For proxy endpoints: Set in proxy.ts before response forwarding

This prevents misleading header values during model selection or provider fallback scenarios.

Source Files and Implementation Details

File Purpose
server/src/lib/header-value.ts Defines safeHeaderValue() and routedViaValue() for header sanitization
server/src/routes/responses.ts Attaches header for OpenAI-compatible chat completion streams
server/src/routes/proxy.ts Attaches header for generic proxy requests and cache hits
docs/api.md Documents header behavior for API consumers (line 60)

Summary

  • The X-Routed-Via header identifies the actual provider platform and model serving each request
  • Format: <platform>/<model> with ASCII-only values (percent-encoded when needed)
  • Cache hits return the literal value cache instead of provider details
  • Sanitization occurs in header-value.ts via the routedViaValue function
  • Timing: Header is set immediately before streaming begins, ensuring accurate routing information

Frequently Asked Questions

What does the X-Routed-Via header value look like for a standard request?

The value follows the pattern platform/model, such as groq/llama-3.3-70b-versatile or anthropic/claude-3-sonnet-20240229. This tells you both which provider's infrastructure handled the request and which specific model variant was invoked.

Why does the X-Routed-Via header sometimes contain percent-encoded characters?

Non-ASCII characters in provider or model names are automatically percent-encoded by the safeHeaderValue sanitizer in server/src/lib/header-value.ts. This ensures HTTP header compliance while preserving the full identity information—use decodeURIComponent() to recover the original string.

How can I tell if my response came from cache instead of live inference?

When FreeLLMAPI serves a request from its internal cache, the X-Routed-Via header is set to the literal string cache rather than a platform/model value. This behavior is implemented in server/src/routes/proxy.ts and allows immediate distinction between cached and live responses.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →