> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zespan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenRouter

> Trace calls made through OpenRouter's unified API in TypeScript and Python with wrapOpenRouter() or patch_openrouter().

<Note>
  Available for: **Python** and **TypeScript**.
</Note>

OpenRouter provides a unified API for 200+ models. Wrap your OpenRouter client with `wrapOpenRouter()` (TypeScript) to trace every call, regardless of which underlying model is used — or patch the `openai` module with `patch_openrouter()` (Python), since OpenRouter uses an OpenAI-compatible API.

## Installation

<CodeGroup>
  ```bash TypeScript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  npm install @zespan/sdk openai
  ```

  ```bash Python theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  pip install zespan openai
  ```
</CodeGroup>

OpenRouter uses an OpenAI-compatible API — install the `openai` package as the client in both languages.

## Setup

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  import OpenAI from "openai";
  import { zespan } from "@zespan/sdk";

  zespan.init({ apiKey: process.env.ZESPAN_API_KEY! });

  const openrouter = zespan.wrapOpenRouter(
    new OpenAI({
      baseURL: "https://openrouter.ai/api/v1",
      apiKey: process.env.OPENROUTER_API_KEY!,
    })
  );
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  import os
  import zespan

  zespan.init(api_key=os.environ["ZESPAN_API_KEY"])
  zespan.patch_openrouter()

  import openai  # import after patching
  client = openai.OpenAI(
      base_url="https://openrouter.ai/api/v1",
      api_key=os.environ["OPENROUTER_API_KEY"],
  )
  ```
</CodeGroup>

<Note>
  In Python, `patch_openrouter()` is an alias for `patch_openai()` — it monkey-patches the `openai` module's chat completions method globally rather than wrapping a single client instance. This means: (1) any `openai.OpenAI()` client in your process is traced after calling it, whether it points at OpenRouter's `base_url` or not; (2) traced events are tagged `provider: "openai"`, not `provider: "openrouter"`; and (3) cost is calculated from token counts and generic pricing, not from OpenRouter's own reported cost. The TypeScript `wrapOpenRouter()` wraps only the client instance you pass it, tags events `provider: "openrouter"`, and prefers OpenRouter's actual reported cost (see below). There is currently no separate Python codepath that gives OpenRouter-specific cost or provider tagging — `patch_openrouter()` and `patch_openai()` are the same function.
</Note>

## Example

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  const response = await openrouter.chat.completions.create({
    model: "anthropic/claude-sonnet-4-6",
    messages: [{ role: "user", content: "What model are you?" }],
  });
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  response = client.chat.completions.create(
      model="anthropic/claude-sonnet-4-6",
      messages=[{"role": "user", "content": "What model are you?"}],
  )
  ```
</CodeGroup>

## What gets captured

| Field                  | Details                                                                                                             | TypeScript   | Python                                                                                  |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------ | --------------------------------------------------------------------------------------- |
| Model                  | The OpenRouter model identifier (e.g. `anthropic/claude-sonnet-4-6`)                                                | Yes          | Yes                                                                                     |
| Input tokens           | From the `usage` response field                                                                                     | Yes          | Yes                                                                                     |
| Output tokens          | From the `usage` response field                                                                                     | Yes          | Yes                                                                                     |
| Cost                   | OpenRouter's reported cost (`usage.cost` or the `x-ratelimit-cost` header), falling back to token-based calculation | Yes          | No — always token-based, since `patch_openrouter()` reuses the generic OpenAI cost path |
| Provider tag on events | The event's `provider` field                                                                                        | `openrouter` | `openai`                                                                                |
| Latency                | Total request duration                                                                                              | Yes          | Yes                                                                                     |

<Note>
  Cost reporting accuracy in TypeScript depends on whether OpenRouter returns cost data in the response. For most popular models it does. For custom or fine-tuned routes, token-based calculation is used as a fallback.
</Note>
