Gemini API: text and video with BetterToken
Call Gemini through BetterToken with OpenAI Chat Completions or the native Gemini API. Includes authentication, SDKs, streaming, tools, video input, and troubleshooting.
Use gemini-3.8-flash and gemini-4-argon with your BetterToken API Key. Both interfaces support text, video, streaming, and tool calls with tool results.
Choose an interface
| Interface | Base URL | When to use it |
|---|---|---|
| OpenAI-compatible | https://bettertoken.ai/v1 | Your application uses Chat Completions or the OpenAI SDK. |
| Gemini native | https://bettertoken.ai | Your application uses Gemini request fields or Google GenAI SDKs. |
All examples use gemini-3.8-flash. Replace it with gemini-4-argon to use the other model. For current pricing, see the model plaza. For image generation, see the separate Nano Banana guide.
Authentication
Create a BetterToken API Key, then replace YOUR_API_KEY below. Run this in the same terminal as the examples.
export BETTERTOKEN_API_KEY="YOUR_API_KEY"| Interface | Authentication |
|---|---|
| OpenAI-compatible | Authorization: Bearer $BETTERTOKEN_API_KEY |
| Gemini native | x-goog-api-key: $BETTERTOKEN_API_KEY (recommended), or Authorization: Bearer $BETTERTOKEN_API_KEY |
A Google AI Studio key does not work here. Use your BetterToken API Key. The native interface also accepts ?key=, but avoid it because URLs can appear in logs.
OpenAI-compatible interface
Send requests to POST https://bettertoken.ai/v1/chat/completions. SDKs use the Base URL https://bettertoken.ai/v1 and append /chat/completions themselves.
curl: basic request
curl --fail-with-body "https://bettertoken.ai/v1/chat/completions" \ -H "Authorization: Bearer $BETTERTOKEN_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "model": "gemini-3.8-flash", "messages": [{"role": "user", "content": "Explain why the sky is blue."}] }'Read text from choices[0].message.content. For curl streaming, add "stream": true to the JSON body and use curl --no-buffer.
Python: basic request and streaming
Install the OpenAI SDK in your Python environment, then run the Python example.
python -m pip install openaiThe streaming request uses stream=True. Read text from each chunk’s choices[0].delta.content.
import osfrom openai import OpenAI
client = OpenAI( api_key=os.environ["BETTERTOKEN_API_KEY"], base_url="https://bettertoken.ai/v1",)messages = [{"role": "user", "content": "Explain why the sky is blue."}]
response = client.chat.completions.create( model="gemini-3.8-flash", messages=messages,)print(response.choices[0].message.content)
stream = client.chat.completions.create( model="gemini-3.8-flash", messages=messages, stream=True,)for chunk in stream: if chunk.choices: print(chunk.choices[0].delta.content or "", end="", flush=True)print()Tool calling
Declare functions in tools with type: "function", a function name, and a JSON Schema in parameters. When the assistant returns tool_calls, run the requested functions in your application.
Keep the complete assistant message, including tool_calls, in the conversation. Append a role: "tool" message for each result. Set its tool_call_id to the matching call ID and put the result in content. Send the updated messages and tools to Chat Completions again.
For image input on this interface, use an image_url content part with an HTTP URL or a data URL, as with other models.
Gemini native interface
For Google GenAI SDKs, set Base URL to https://bettertoken.ai. Do not add /v1beta: the SDK appends it. Raw HTTP requests use the full paths below.
curl: generateContent
curl --fail-with-body \ "https://bettertoken.ai/v1beta/models/gemini-3.8-flash:generateContent" \ -H "x-goog-api-key: $BETTERTOKEN_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "contents": [{"role": "user", "parts": [{"text": "Explain why the sky is blue."}]}] }'Read text from candidates[].content.parts[].text.
curl: streaming
streamGenerateContent?alt=sse returns Server-Sent Events (SSE). --no-buffer displays events as they arrive.
curl --fail-with-body --no-buffer \ "https://bettertoken.ai/v1beta/models/gemini-3.8-flash:streamGenerateContent?alt=sse" \ -H "x-goog-api-key: $BETTERTOKEN_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "contents": [{"role": "user", "parts": [{"text": "Explain why the sky is blue."}]}] }'Python: Google GenAI SDK
Install google-genai in your Python environment. The example makes a basic request followed by a streaming request.
python -m pip install google-genaiimport osfrom google import genaifrom google.genai import types
client = genai.Client( api_key=os.environ["BETTERTOKEN_API_KEY"], http_options=types.HttpOptions(base_url="https://bettertoken.ai"),)
response = client.models.generate_content( model="gemini-3.8-flash", contents="Explain why the sky is blue.",)print(response.text)
for chunk in client.models.generate_content_stream( model="gemini-3.8-flash", contents="Explain why the sky is blue.",): print(chunk.text or "", end="", flush=True)print()Node.js: Google GenAI SDK
Install @google/genai. Save the JavaScript example as gemini.mjs, then run node gemini.mjs.
npm install @google/genaiimport { GoogleGenAI } from "@google/genai";
const client = new GoogleGenAI({ apiKey: process.env.BETTERTOKEN_API_KEY, httpOptions: { baseUrl: "https://bettertoken.ai" },});
const response = await client.models.generateContent({ model: "gemini-3.8-flash", contents: "Explain why the sky is blue.",});console.log(response.text);
const stream = await client.models.generateContentStream({ model: "gemini-3.8-flash", contents: "Explain why the sky is blue.",});for await (const chunk of stream) { process.stdout.write(chunk.text ?? "");}console.log();Tool calling
Declare functions in tools[].functionDeclarations. Read the requested function and arguments from functionCall in the model’s response parts, then run the function in your application.
Keep the complete model content in contents. Append a role: "user" content entry whose parts contain functionResponse with the matching function name and a response object holding the result. Send the updated contents and tools to generateContent again.
List models
Use GET https://bettertoken.ai/v1beta/models to list models.
curl --fail-with-body "https://bettertoken.ai/v1beta/models" \ -H "x-goog-api-key: $BETTERTOKEN_API_KEY"Video input
Before sending either example, replace REPLACE_WITH_VIDEO_BASE64 with your video’s base64 on a single line. The examples use an MP4 clip; for another format, change the MIME type and filename to match.
Accepted MIME types: video/mp4, video/mpeg, video/mpg, video/mov, video/avi, video/wmv, video/flv, video/mpegps.
Send video inline as base64 in the request body. Base64 makes the body about one third larger than the file. Use short or compressed clips; very large requests can return HTTP 413.
The OpenAI-compatible file.file_data includes the data:video/mp4;base64, prefix. Native inlineData.data contains only base64, without that prefix.
Chat Completions: inline file
curl --fail-with-body "https://bettertoken.ai/v1/chat/completions" \ -H "Authorization: Bearer $BETTERTOKEN_API_KEY" \ -H "Content-Type: application/json" \ --data-binary @- <<'JSON'{ "model": "gemini-3.8-flash", "messages": [{ "role": "user", "content": [ {"type": "file", "file": { "filename": "clip.mp4", "file_data": "data:video/mp4;base64,REPLACE_WITH_VIDEO_BASE64" }}, {"type": "text", "text": "Describe what happens in this video."} ] }]}JSONGemini native: inlineData
curl --fail-with-body \ "https://bettertoken.ai/v1beta/models/gemini-3.8-flash:generateContent" \ -H "x-goog-api-key: $BETTERTOKEN_API_KEY" \ -H "Content-Type: application/json" \ --data-binary @- <<'JSON'{ "contents": [{ "role": "user", "parts": [ {"inlineData": {"mimeType": "video/mp4", "data": "REPLACE_WITH_VIDEO_BASE64"}}, {"text": "Describe what happens in this video."} ] }]}JSONUsage and billing
Chat Completions: reasoning/thinking tokens are included in completion_tokens and billed as output.
Gemini native: usageMetadata.thoughtsTokenCount is billed as output. cachedContentTokenCount reports cached input. Video counts as input tokens; promptTokensDetails identifies it with modality VIDEO.
Limitations
POST /v1/responsesdoes not support these Gemini models. Codex CLI and other clients that only use the Responses API cannot call them. Use Chat Completions or the native interface.file_idreferences and Google File API uploads usingfileData.fileUriare not supported. Send video inline as base64.
Troubleshooting
| Error | What to do |
|---|---|
401 | Check the BetterToken API Key and authentication header. Replace a wrong or missing Key. |
413 | The request body is too large. Shorten or compress the video. |
429 | Rate limiting or temporary upstream capacity. Retry with increasing delays (backoff). |
503 with model_not_found | No capacity is available right now. Retry later. |
For other errors, see API errors.

