# Gemini native

> generateContent and streamGenerateContent in the native Gemini format.

Generates content in the native Gemini format. Works with the official Gemini SDK (google-genai).

## Method and path

`POST /v1beta/models/{model}:generateContent`

`POST /v1beta/models/{model}:streamGenerateContent`

Gemini SDKs take the base URL `https://api.relayvia.dev`. Put the model name in the path and send the key as `x-goog-api-key: sk-...` or `Authorization: Bearer sk-...`.

## Common parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `model` | `string` | Yes | Official model name, in the path. |
| `alt` | `string` | No | `sse` on streamGenerateContent for Server-Sent Events; without it the stream is a JSON array. |
| `contents` | `array` | Yes | The conversation: user and model turns made of parts. |
| `systemInstruction` | `object` | No | System instruction. |
| `generationConfig` | `object` | No | Generation settings, including `maxOutputTokens` (it decides the reservation) and `candidateCount`. |
| `tools` | `array` | No | Only `functionDeclarations`. |
| `toolConfig` | `object` | No | Function calling mode. |

Requests are forwarded in the original format, so the original API's parameters work unless the next section says otherwise. This table lists the common ones; see the [official reference](https://ai.google.dev/api/generate-content) for the rest.

## Differences from the original API

- Only `generateContent` and `streamGenerateContent` are served; other actions such as countTokens and embedContent return 404.
- Cached content (`cachedContent`) and files stored at Google (`file_data.file_uri` pointing to `files/...`, generativelanguage.googleapis.com or `gs://`) return 400 `unsupported_parameter`. Remote files other than images are refused too; send the data inline with `inline_data`.
- Tools only accept `functionDeclarations`. Google Search, code execution and other built-in tools return 400 `unsupported_parameter`.
- `candidateCount` must be a positive integer, otherwise 400 `invalid_request`. The reservation and the charge cover every candidate.
- `modelVersion` in the response is the model name you sent.
- A non-streaming request with no response within 95 seconds returns 500 `upstream_timeout`; use streaming for long outputs. Or send the header `X-Robi-Keepalive: 1`: if there is no response within 30 seconds you get a 200 right away and a space every 15 seconds until the JSON arrives, and a later failure arrives as an error object in the body.

## Request examples

**cURL**

```bash
curl https://api.relayvia.dev/v1beta/models/gemini-3.6-flash:generateContent \
  -H "x-goog-api-key: sk-..." \
  -H "Content-Type: application/json" \
  -d '{"contents":[{"role":"user","parts":[{"text":"Hello!"}]}]}'
```

**Python**

```python
from google import genai

client = genai.Client(api_key="sk-...", http_options={"base_url": "https://api.relayvia.dev"})
resp = client.models.generate_content(model="gemini-3.6-flash", contents="Hello!")
print(resp.text)
```

**JavaScript**

```javascript
import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({ apiKey: "sk-...", httpOptions: { baseUrl: "https://api.relayvia.dev" } });
const resp = await ai.models.generateContent({ model: "gemini-3.6-flash", contents: "Hello!" });
console.log(resp.text);
```

## Response and streaming examples

**Response**

```json
{
  "candidates": [
    {
      "content": {
        "role": "model",
        "parts": [
          {
            "text": "Hello! How can I help?"
          }
        ]
      },
      "finishReason": "STOP"
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 9,
    "candidatesTokenCount": 8,
    "totalTokenCount": 17
  },
  "modelVersion": "gemini-3.6-flash"
}
```

**Streaming**

```text
data: {"candidates":[{"content":{"role":"model","parts":[{"text":"Hello!"}]}}],"modelVersion":"gemini-3.6-flash"}

data: {"candidates":[{"content":{"role":"model","parts":[{"text":" How can I help?"}]},"finishReason":"STOP"}],"usageMetadata":{"promptTokenCount":9,"candidatesTokenCount":8,"totalTokenCount":17},"modelVersion":"gemini-3.6-flash"}
```

## Errors this endpoint returns

| HTTP | code | When |
| --- | --- | --- |
| `400` | `invalid_request` | A parameter is invalid. If the model rejected it, the message is this sentence, or `Invalid value for parameter <param>.` with `param` set. |
| `400` | `unsupported_parameter` | The request uses something Relayvia does not offer: stored server-side state, a hosted tool or a remote file. `param` names it. |
| `400` | `invalid_media` | The model reports that an input image or file format is not supported. |
| `400` | `media_unreachable` | The model could not read the media URL you sent. |
| `400` | `content_policy` | The input did not pass the model's safety review. If the model does not say whether the input or the output was refused, the message is `Content did not pass safety review.` |
| `400` | `content_policy_output` | The model generated a result, but the result did not pass safety review. Your input was not the problem. |
| `401` | `invalid_api_key` | The API key does not exist, is disabled or has expired. |
| `402` | `insufficient_quota` | Not enough credits: the account's credits, the key's limit, the team member's limit or an account spend limit cannot cover the request, or the account is frozen. |
| `403` | `forbidden` | The key may not use this model, the source IP is not on the allowlist, or the account is disabled. |
| `404` | `model_not_found` | The model is not listed. |
| `413` | `request_too_large` | The request body is over 20 MB, or the model reports that the input exceeds its context or size limit (then with this sentence). |
| `429` | `rate_limited` | Too many requests: per IP, per key, per account, or too many requests in progress at once. |
| `500` | `model_price_error` | The model has no price yet, so it cannot be called. |
| `500` | `upstream_error` | Relayvia tried other model services and every attempt failed. |
| `503` | `no_available_channel` | No model service is available for this model right now. |
| `503` | `service_busy` | Every model service for this model reported being busy. |
| `500` | `upstream_timeout` | Every attempt timed out. |

Every code, its fixed message and what to do are on the [error codes](https://relayvia.dev/docs/errors) page.
