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

# Google Gemini Proxy

> Route Google Gemini API requests through MetrixLLM for observability, rate limiting, and provider fallback.

The MetrixLLM gateway provides a drop-in proxy for Google's Generative Language API. Use the Gemini REST API or SDKs by changing only the Base URL and API key.

## Base URL

```text theme={null}
https://gateway.metrixllm.com
```

## Authentication

All requests require a MetrixLLM API key. The gateway accepts both formats:

```text theme={null}
x-api-key: sk-metrix-YOUR_API_KEY
```

```text theme={null}
Authorization: Bearer sk-metrix-YOUR_API_KEY
```

<Warning>
  Do **not** use your Google AI API key. The gateway authenticates requests using MetrixLLM keys (`sk-metrix-*` prefix). The gateway then uses its own provider keys (or your BYOK keys) to call Google.
</Warning>

### Internal Authentication

For backend-to-gateway communication, the gateway supports internal authentication:

| Header                  | Required | Description                                                           |
| ----------------------- | -------- | --------------------------------------------------------------------- |
| `x-metrix-internal`     | Yes      | Shared secret matching `HEALTH_CHECK_SECRET` (timing-safe comparison) |
| `x-metrix-workspace-id` | Yes\*    | Workspace UUID (use `x-workspace-id` as fallback)                     |

Internal auth skips the standard API key validation. Used by the MetrixLLM backend for playground, replay, and batch operations.

## Endpoints

| Method | Path                                            | Description                                     |
| ------ | ----------------------------------------------- | ----------------------------------------------- |
| `POST` | `/gemini/v1beta/models/{model}:generateContent` | Generate content (returns Gemini-native format) |

The `{model}` parameter is extracted from the URL path. Supported models include `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-2.0-flash`, and others configured in your workspace.

***

## Request Headers

Every request supports these headers:

| Header          | Type     | Required | Description                                           |
| --------------- | -------- | -------- | ----------------------------------------------------- |
| `x-api-key`     | `string` | Yes\*    | `sk-metrix-{key}` — MetrixLLM API key                 |
| `Authorization` | `string` | Yes\*    | `Bearer sk-metrix-{key}` — alternative to `x-api-key` |
| `Content-Type`  | `string` | Yes      | Must be `application/json`                            |

**Session Tracing**

Use these headers to group related requests into sessions and trace spans:

| Header                | Description                                                                  | Stored In                   |
| --------------------- | ---------------------------------------------------------------------------- | --------------------------- |
| `metrix-session-id`   | Unique session identifier — groups related requests into a traceable session | `workspace_logs.session_id` |
| `metrix-parent-id`    | Links a request to a parent span in the session trace                        | `workspace_logs.parent_id`  |
| `metrix-session-name` | Human-readable name for the span (for dashboard display)                     | `workspace_logs.span_name`  |

**Custom Properties**

Attach up to 10 custom metadata properties per request:

| Header Pattern          | Description                                                                        |
| ----------------------- | ---------------------------------------------------------------------------------- |
| `metrix-property-{key}` | Custom metadata property. Used for rate limit targeting, analytics, and filtering. |

Example: `metrix-property-team: engineering`, `metrix-property-environment: production`

**Worker-to-Gateway**

These headers are set by the Cloudflare Edge Worker when routing through the Durable Object balance system:

| Header                 | Description                                                                        |
| ---------------------- | ---------------------------------------------------------------------------------- |
| `x-balance`            | Workspace credit balance from Durable Object                                       |
| `x-internal-signature` | HMAC-SHA256 signature of `{workspace_id}:{balance}` verified with `DO_SYNC_SECRET` |

**IP Detection**

| Header            | Description                                                                                                          |
| ----------------- | -------------------------------------------------------------------------------------------------------------------- |
| `x-forwarded-for` | Client IP address (first IP in comma-separated list). Trusted only when peer is a private/local address.             |
| `x-real-ip`       | Fallback client IP header. Same trust rules as `x-forwarded-for`.                                                    |
| `cf-ipcountry`    | Cloudflare-specific country code of the connecting client (e.g. `US`, `IN`). Used for request logging and analytics. |

***

## Generate Content

### URL Format

```text theme={null}
POST /gemini/v1beta/models/{model}:generateContent
```

Examples:

* `/gemini/v1beta/models/gemini-2.5-pro:generateContent`
* `/gemini/v1beta/models/gemini-2.5-flash:generateContent`
* `/gemini/v1beta/models/gemini-2.0-flash:generateContent`

### Request Body

Send standard Gemini `generateContent` requests. The gateway accepts all standard Gemini fields plus MetrixLLM-specific extensions.

| Field               | Type                | Required | Description                                                        |
| ------------------- | ------------------- | -------- | ------------------------------------------------------------------ |
| `contents`          | `array`             | Yes      | Array of content objects (conversation turns)                      |
| `systemInstruction` | `object`            | No       | System instruction (top-level)                                     |
| `generationConfig`  | `object`            | No       | Generation parameters (temperature, maxOutputTokens, etc.)         |
| `tools`             | `array`             | No       | Tool definitions (function declarations, Google Search)            |
| `toolConfig`        | `object`            | No       | Tool selection configuration                                       |
| `mode`              | `string`            | No       | Key selection: `"auto"` (default), `"byok"`, or `"native"`         |
| `web_search`        | `boolean \| string` | No       | Enable web search: `true` (standard), `"native"` (Google built-in) |

### Content Format

Each content object represents a turn in the conversation:

```json theme={null}
{
  "contents": [
    {
      "role": "user",
      "parts": [{"text": "What is the capital of France?"}]
    }
  ]
}
```

Use `"model"` for assistant turns and `"user"` for user turns.

### System Instruction

```json theme={null}
{
  "systemInstruction": {
    "parts": [
      {"text": "You are a helpful assistant."}
    ]
  }
}
```

### Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://gateway.metrixllm.com/gemini/v1beta/models/gemini-2.5-pro:generateContent" \
    -H "Content-Type: application/json" \
    -H "x-api-key: sk-metrix-YOUR_API_KEY" \
    -H "metrix-session-id: session_abc123" \
    -H "metrix-session-name: Content Generation" \
    -d '{
      "contents": [
        {
          "role": "user",
          "parts": [{"text": "What is the capital of France?"}]
        }
      ],
      "systemInstruction": {
        "parts": [{"text": "You are a helpful assistant."}]
      },
      "generationConfig": {
        "maxOutputTokens": 1024,
        "temperature": 0.7
      }
    }'
  ```

  ```python Python theme={null}
  import requests

  url = "https://gateway.metrixllm.com/gemini/v1beta/models/gemini-2.5-pro:generateContent"
  headers = {
      "Content-Type": "application/json",
      "x-api-key": "sk-metrix-YOUR_API_KEY",
      "metrix-session-id": "session_abc123",
      "metrix-session-name": "Content Generation",
  }
  payload = {
      "contents": [
          {"role": "user", "parts": [{"text": "What is the capital of France?"}]}
      ],
      "systemInstruction": {
          "parts": [{"text": "You are a helpful assistant."}]
      },
      "generationConfig": {
          "maxOutputTokens": 1024,
          "temperature": 0.7,
      },
  }

  response = requests.post(url, headers=headers, json=payload)
  data = response.json()
  print(data["candidates"][0]["content"]["parts"][0]["text"])
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    "https://gateway.metrixllm.com/gemini/v1beta/models/gemini-2.5-pro:generateContent",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": "sk-metrix-YOUR_API_KEY",
        "metrix-session-id": "session_abc123",
        "metrix-session-name": "Content Generation",
      },
      body: JSON.stringify({
        contents: [
          { role: "user", parts: [{ text: "What is the capital of France?" }] },
        ],
        systemInstruction: {
          parts: [{ text: "You are a helpful assistant." }],
        },
        generationConfig: {
          maxOutputTokens: 1024,
          temperature: 0.7,
        },
      }),
    }
  );

  const data = await response.json();
  console.log(data.candidates[0].content.parts[0].text);
  ```
</CodeGroup>

### Response Body

```json theme={null}
{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "The capital of France is Paris."
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP"
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 15,
    "candidatesTokenCount": 8,
    "totalTokenCount": 23
  }
}
```

### Response Headers

Every successful response includes these headers:

| Header                           | Description                                                             |
| -------------------------------- | ----------------------------------------------------------------------- |
| `Content-Type`                   | Always `application/json`                                               |
| `X-Metrix-Provider`              | Resolved upstream provider (e.g. `google`, `openai`)                    |
| `X-Metrix-Model`                 | Actual model used for the request                                       |
| `X-Metrix-Cache-Status`          | `"HIT"` or `"miss"` (semantic cache)                                    |
| `X-Metrix-Retry-Count`           | Number of retry attempts (0 if none)                                    |
| `X-Metrix-Retry-Status`          | `"success"`, `"failed"`, or `"not_triggered"`                           |
| `X-Metrix-Fallback`              | `"true"` if a fallback provider was used (only present when applicable) |
| `X-RateLimit-Limit`              | Configured limit for the rate window                                    |
| `X-RateLimit-Remaining`          | Remaining quota in the current window                                   |
| `X-RateLimit-Requests-Remaining` | Remaining requests in the current rate window                           |
| `X-RateLimit-Tokens-Remaining`   | Remaining tokens in the current rate window                             |

On cache HIT responses, only `Content-Type` and `X-Metrix-Cache-Status: HIT` are returned.

On rate limited responses (`429 Too Many Requests`):

| Header                         | Description                                                           |
| ------------------------------ | --------------------------------------------------------------------- |
| `Retry-After`                  | Seconds to wait before retrying                                       |
| `X-RateLimit-{type}-Limit`     | Maximum limit (e.g. `X-RateLimit-rpm-Limit`, `X-RateLimit-tpm-Limit`) |
| `X-RateLimit-{type}-Remaining` | Remaining count in the current window                                 |
| `X-RateLimit-Reset`            | Seconds until the rate window resets                                  |

***

## Generation Configuration

Configure generation parameters in the `generationConfig` object:

| Field             | Type      | Description                                                 |
| ----------------- | --------- | ----------------------------------------------------------- |
| `temperature`     | `number`  | Sampling temperature (0.0 - 2.0)                            |
| `topP`            | `number`  | Nucleus sampling parameter                                  |
| `topK`            | `integer` | Top-k sampling parameter                                    |
| `maxOutputTokens` | `integer` | Maximum output tokens                                       |
| `stopSequences`   | `array`   | Stop sequences                                              |
| `thinkingConfig`  | `object`  | Extended thinking configuration (see [Thinking](#thinking)) |

### Example

```json theme={null}
{
  "contents": [
    {"role": "user", "parts": [{"text": "Explain quantum computing."}]}
  ],
  "generationConfig": {
    "temperature": 0.7,
    "topP": 0.9,
    "topK": 40,
    "maxOutputTokens": 2048
  }
}
```

***

## Thinking (Extended Thinking)

Enable extended thinking for deeper reasoning. The gateway converts between Gemini's `thinkingConfig` and other provider formats automatically.

```json theme={null}
{
  "contents": [
    {"role": "user", "parts": [{"text": "Explain quantum entanglement in detail."}]}
  ],
  "generationConfig": {
    "maxOutputTokens": 16000,
    "thinkingConfig": {
      "thinkingBudget": 10240
    }
  }
}
```

| Field                           | Type      | Description                                                      |
| ------------------------------- | --------- | ---------------------------------------------------------------- |
| `thinkingConfig.thinkingBudget` | `integer` | Maximum tokens allocated to thinking (higher = deeper reasoning) |

<Note>
  When using the gateway's generic proxy (`/v1/chat/completions`), you can use a simplified `thinking` field: `"low"` (2048 tokens), `"medium"` (10240 tokens), or `"high"` (20480 tokens). The gateway converts these to the appropriate provider-specific format.
</Note>

***

## Tool Use

Define tools using Gemini's native format with `functionDeclarations`.

```json theme={null}
{
  "contents": [
    {"role": "user", "parts": [{"text": "What is the weather in San Francisco?"}]}
  ],
  "tools": [
    {
      "functionDeclarations": [
        {
          "name": "get_weather",
          "description": "Get current weather for a location",
          "parameters": {
            "type": "OBJECT",
            "properties": {
              "location": {
                "type": "STRING",
                "description": "City name"
              }
            },
            "required": ["location"]
          }
        }
      ]
    }
  ]
}
```

### Tool Configuration

Control tool selection with `toolConfig`:

| Mode     | Behavior                                 |
| -------- | ---------------------------------------- |
| `"AUTO"` | Model decides whether to use a tool      |
| `"ANY"`  | Model must use one of the provided tools |
| `"NONE"` | Model must not use any tools             |

***

## Web Search

Enable web search to give the model access to real-time information.

| Value             | Behavior                                                         |
| ----------------- | ---------------------------------------------------------------- |
| `true`            | Performs a web search and injects results into the system prompt |
| `"native"`        | Uses Google's built-in `google_search` tool                      |
| `false` or absent | No web search                                                    |

### Native Web Search Example

Include `google_search` in your tools array:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://gateway.metrixllm.com/gemini/v1beta/models/gemini-2.5-pro:generateContent" \
    -H "Content-Type: application/json" \
    -H "x-api-key: sk-metrix-YOUR_API_KEY" \
    -d '{
      "contents": [
        {"role": "user", "parts": [{"text": "What are the latest developments in AI?"}]}
      ],
      "tools": [
        {"google_search": {}}
      ]
    }'
  ```

  ```python Python theme={null}
  import requests

  url = "https://gateway.metrixllm.com/gemini/v1beta/models/gemini-2.5-pro:generateContent"
  headers = {
      "Content-Type": "application/json",
      "x-api-key": "sk-metrix-YOUR_API_KEY",
  }
  payload = {
      "contents": [
          {"role": "user", "parts": [{"text": "What are the latest developments in AI?"}]}
      ],
      "tools": [{"google_search": {}}],
  }

  response = requests.post(url, headers=headers, json=payload)
  data = response.json()
  print(data["candidates"][0]["content"]["parts"][0]["text"])
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    "https://gateway.metrixllm.com/gemini/v1beta/models/gemini-2.5-pro:generateContent",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": "sk-metrix-YOUR_API_KEY",
      },
      body: JSON.stringify({
        contents: [
          { role: "user", parts: [{ text: "What are the latest developments in AI?" }] },
        ],
        tools: [{ google_search: {} }],
      }),
    }
  );

  const data = await response.json();
  console.log(data.candidates[0].content.parts[0].text);
  ```
</CodeGroup>

***

## Prompt Management

Use `prompt_id` to reference a stored prompt template via the generic proxy endpoint. The gateway fetches the template, renders `{{variable}}` placeholders with values from `inputs`, and sends the rendered messages to the provider.

```json theme={null}
{
  "model": "gemini-2.5-pro",
  "prompt_id": "prompt_abc123",
  "inputs": {
    "user_name": "Alice",
    "topic": "quantum computing"
  }
}
```

***

## Error Responses

Errors return a JSON body. The HTTP status code indicates the error type.

| Status | Meaning                                                      |
| ------ | ------------------------------------------------------------ |
| `400`  | Invalid request (missing model, malformed body, invalid URL) |
| `401`  | Invalid or missing API key                                   |
| `402`  | Insufficient credits                                         |
| `403`  | Workspace disabled, IP not allowed, or model not enabled     |
| `404`  | Model not recognized                                         |
| `429`  | Rate limit exceeded                                          |
| `446`  | Guardrail block (request blocked by content policy)          |
| `500`  | Internal gateway error                                       |
| `502`  | Upstream provider error                                      |
| `503`  | Provider circuit breaker open                                |

### Error Response Format

```json theme={null}
{
  "error": "Invalid URL format. Expected: /gemini/v1beta/models/{model}:generateContent",
  "type": "invalid_request_error",
  "code": "INVALID_URL"
}
```

***

## Retry and Fallback

The gateway automatically retries failed requests and falls back to alternative providers:

* **Retry**: Retries on `429`, `500`, `502`, `503`, `504` status codes with exponential backoff
* **Fallback**: If the primary provider fails, the gateway tries the next configured provider in the chain
* **Circuit Breaker**: Providers with repeated failures are temporarily skipped (circuit opens for 60 seconds)
* **Cerebras Fallback**: If all configured providers fail on system errors, the gateway falls back to Cerebras (if enabled)

These features are transparent to your application -- you receive a single successful response.

***

## Mode Override

Control provider key selection with the `mode` field:

| Value      | Behavior                                                                        |
| ---------- | ------------------------------------------------------------------------------- |
| `"auto"`   | Default. Uses your BYOK key if configured, otherwise uses MetrixLLM native key. |
| `"byok"`   | Forces use of your own API key. Fails if no key is configured for the provider. |
| `"native"` | Forces use of MetrixLLM's managed key. Skips BYOK keys entirely.                |

```json theme={null}
{
  "contents": [
    {"role": "user", "parts": [{"text": "Hello!"}]}
  ],
  "mode": "native"
}
```

***

## Using with Google SDKs

You can use the Google AI Python SDK with the gateway by setting the base URL:

```python theme={null}
from google import genai

client = genai.Client(
    api_key="sk-metrix-YOUR_API_KEY",
    http_options={"base_url": "https://gateway.metrixllm.com/gemini"},
)

response = client.models.generate_content(
    model="gemini-2.5-pro",
    contents="What is the capital of France?",
)

print(response.text)
```
