POST /api/{provider}/v1/chat/completions

Relays a provider’s own chat-completions payload and returns that provider’s own response, byte for byte. Respan authenticates the request, applies your limits and budgets, and writes the log row. It does not rewrite the request or recompute usage.

Use this when correctness matters more than portability: agent frameworks pinned to one provider’s exact semantics, tuned tool-calling behavior, or any payload where a translation layer is a liability. For one request shape across many providers, use the [unified router](/content/docs/documentation/features/gateway/routing-and-passthrough/index.html) at `POST /api/chat/completions` instead. That endpoint normalizes; this one does not.

`{provider}` is the provider id (for example `openai`, `xai`, `groq`). `Authorization` carries your **Respan** key, not the provider’s.

Grok is the same call with a different path segment:

With the OpenAI SDK, repoint `base_url` and pass your Respan key. Nothing else changes:

## What is guaranteed

| Aspect | Behavior |
| --- | --- |
| **Request body** | Forwarded unchanged. Unknown fields, new provider fields, and provider-only extensions all survive. Only `respan_params` is removed. |
| **Usage** | The provider’s own numbers, including cached-token and provider-specific fields. Never recomputed or estimated. |
| **Invalid requests** | Stay invalid. `store: false` with `metadata` fails exactly as it fails calling the provider directly, rather than being normalized into a success. |
| **Response body** | The provider’s bytes, preserving key order and formatting. Streaming is relayed frame by frame. |

## Headers

**Forwarded upstream:** `accept`, `accept-language`, `content-type`, `user-agent`, plus that provider’s `x-{provider}-*` extension headers. Everything else (cookies, Respan’s own headers) is dropped, so nothing leaks to the provider.

**Returned to you:**

| Header | Meaning |
| --- | --- |
| `X-Respan-Log-Id` | Respan log id for this request |
| `X-Respan-Upstream-Request-Id` | The provider’s own request id, for correlating with their support |
| `x-ratelimit-*` | The provider’s rate-limit headers, relayed |
| `retry-after` | Relayed when the provider sends it |

## Errors and limits

Provider errors pass through with the provider’s status code and body, so your existing error handling keeps working. Respan’s own errors:

| Status | Meaning |
| --- | --- |
| `401` | No usable credentials for the provider |
| `404` | Provider is not available as an OpenAI-shaped passthrough |
| `429` | Your Respan key’s rate limit |

Respan imposes no request-body size, context-length, or truncation limit below the provider’s own, and never silently truncates. If a provider limit is exceeded, the provider’s error is returned. The request timeout is 600s so long reasoning calls complete.

## Supported providers

`azure_deepseek`, `azure_openai`, `baseten`, `cerebras`, `chutes`, `deepseek`, `empiriolabs`, `featherless`, `fireworks`, `friendliai`, `gonka24`, `groq`, `inceptron`, `inference_net`, `ionet`, `makora`, `minimax`, `mistral`, `moonshot`, `morphllm`, `nebius`, `nextbit256`, `novita`, `openai`, `openai_compatible`, `openrouter`, `parasail`, `perplexity`, `qwen`, `tera`, `togetherai`, `wafer`, `xai`, `zai`

Providers whose API is not OpenAI-shaped (Anthropic, Google, Bedrock, Cohere) have their own native passthrough endpoints. See [Routing & passthrough](/content/docs/documentation/features/gateway/routing-and-passthrough/index.html).

## OpenRouter

OpenRouter has its own path and uses **your** OpenRouter key rather than an org integration:

`Authorization` is your Respan key; `x-openrouter-api-key` is your OpenRouter key. A missing OpenRouter key returns `400`. OpenRouter’s attribution headers `http-referer` and `x-title` are forwarded so your app still appears on their rankings.
