Gemini API Integration: Two Endpoints, Five Minutes

A copy-paste Gemini API guide: how the OpenAI-compatible endpoint differs from native generateContent, what each unlocks, live pricing and cost math.

The first fork in the road when integrating Gemini is not the API key, it's the endpoint: /v1/chat/completions on one side, /v1beta/models/{model}:generateContent on the other. Both will happily call gemini-3.1-flash-lite-preview, but they don't give you the same capabilities. This post covers the differences, minimal working code for both, real prices and the errors that actually bite.

What the two endpoints really do

The OpenAI-compatible endpoint is a translator. It converts your messages array into Gemini contents, then translates the response back into the OpenAI shape. That translation buys compatibility and costs fidelity. The native endpoint has no translator: what you send is what the model receives.

AspectOpenAI-compatible /v1/chat/completionsNative /v1beta/models/{model}:generateContent
Auth headerAuthorization: Bearer sk-...x-goog-api-key: sk-... (Bearer also accepted)
Message shapemessages: [{role, content}]contents: [{role, parts:[{text}]}]
Rolessystem / user / assistantonly user and model; system prompt via systemInstruction
Multimodalimage_url entries in contentinlineData / fileData inside parts
Streamingstream: true, SSE:streamGenerateContent?alt=sse
Thinking budgetusually not passed throughgenerationConfig.thinkingConfig.thinkingBudget
Structured outputresponse_formatgenerationConfig.responseMimeType
Official SDKopenai package + base_urlgoogle-genai + http_options

Rule of thumb: use the compatible endpoint for tooling, switch to native when you need a Gemini-specific feature. It's the same key on both, so they can coexist.

Step 1: key and endpoints

Create an sk- token in the console, then note two addresses:

  • Compatible base URL: https://api.zaimod.com/v1
  • Native: https://api.zaimod.com/v1beta/models/{model}:generateContent

Full account setup is in the quickstart; let's go straight to code.

Step 2: first request through the compatible endpoint

If you already use the openai package, this is a two-line change:

Python
from openai import OpenAI

client = OpenAI(
    api_key="sk-your-zaimod-key",
    base_url="https://api.zaimod.com/v1",   # the only change
)

resp = client.chat.completions.create(
    model="gemini-3.1-flash-lite-preview",
    messages=[{"role": "user", "content": "Explain vector search in three sentences."}],
)
print(resp.choices[0].message.content)
print(resp.usage)   # prompt_tokens / completion_tokens — keep this for reconciliation

No SDK? Verify the key and network with curl first:

Shell
curl https://api.zaimod.com/v1/chat/completions \
  -H "Authorization: Bearer $ZAIMOD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.1-flash-lite-preview",
    "messages": [{"role": "user", "content": "Hello"}],
    "max_tokens": 256
  }'

A 200 with a usage block means the path works. This single check eliminates most "can't connect" reports, which are almost always a trailing space in the key or a misspelled model name.

Step 3: move to native for the features that matter

Four things the translation layer loses or fuzzes.

System instruction and history

Gemini has no system role. The system prompt lives in systemInstruction, history goes in contents, and role is only user or model:

JSON
{
  "systemInstruction": {"parts": [{"text": "You are a terse technical editor. Output conclusions and evidence only."}]},
  "contents": [
    {"role": "user", "parts": [{"text": "Tighten this: the API is slow."}]},
    {"role": "model", "parts": [{"text": "Average API latency exceeds two seconds."}]},
    {"role": "user", "parts": [{"text": "Shorter."}]}
  ],
  "generationConfig": {"temperature": 0.2, "maxOutputTokens": 512}
}

Multimodal: text and files in the same parts array

JSON
{
  "contents": [{
    "role": "user",
    "parts": [
      {"text": "What is the error in this screenshot?"},
      {"inlineData": {"mimeType": "image/png", "data": "<base64>"}}
    ]
  }]
}

Images, audio and video all use parts; for URLs use fileData. Video analysis is most complete on the Gemini premium group, but that group carries a ×1.5 multiplier — do the math before pointing a long-video job at it.

Streaming requires alt=sse

Shell
curl -N "https://api.zaimod.com/v1beta/models/gemini-3.1-pro-preview:streamGenerateContent?alt=sse" \
  -H "x-goog-api-key: $ZAIMOD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contents": [{"parts": [{"text": "Write a 100-word product launch blurb."}]}]}'

Drop alt=sse and you get a JSON array instead of a stream. Feed that to an SSE parser and the UI renders nothing — the single most common native-endpoint bug.

Thinking budget and JSON output

JSON
{
  "contents": [{"parts": [{"text": "Extract party, amount and signing date from this contract."}]}],
  "generationConfig": {
    "responseMimeType": "application/json",
    "thinkingConfig": {"thinkingBudget": 2048}
  }
}

thinkingBudget drives both reasoning depth and cost. Extraction tasks usually need 1024–2048; only proofs and multi-step math need more. Field-level details are in the Gemini native endpoint docs.

Pricing: model the cost before you ship

Live list prices (USD per 1M tokens, input / output, default group):

ModelInputOutputGood for
gemini-3.1-flash-lite-preview$0.25$1.50classification, extraction, bulk summaries
gemini-2.5-flash$0.30$2.50mixed text + image understanding
gemini-2.5-pro$1.80$15.30long documents, hard reasoning
gemini-3.1-pro-preview$4.00$24.00flagship long-context work
gpt-4o-mini (reference)$0.156$0.624ultra-cheap general fallback

For 2,000 calls a day at 1,500 input and 500 output tokens each, you burn 3M input + 1M output per day:

  • flash-lite: 3 × 0.25 + 1 × 1.50 = $2.25/day, roughly $68/month
  • 2.5-pro: 3 × 1.80 + 1 × 15.30 = $20.70/day, roughly $621/month
  • 3.1-pro: 3 × 4.00 + 1 × 24.00 = $36.00/day, roughly $1,080/month

Same business logic, 30× spread. The fix is boring: ship the whole pipeline on flash-lite, route only the requests it fails to pro. Live numbers are on the pricing page — don't memorise the table, prices move.

The four errors you will hit

ErrorReal causeFix
401 invalid api keytrailing whitespace, or a key from another platformrecopy, watch for newlines
404 model not foundmisspelled model, or not available in your groupuse exact names from the model list
400 contents is not specifiedsent messages to the native endpointswitch to contents + parts
stream arrives as one blob?alt=sse missingadd it, watch with curl -N

429 and "insufficient balance" look similar but need different handling — backoff versus top-up. The decision table lives in billing and error codes.

Which endpoint should you pick

  • Cursor, Cline, Cherry Studio, LangChain: compatible endpoint — they only speak OpenAI
  • Video understanding, thinkingBudget, responseMimeType: native
  • Multi-vendor (GPT + Claude + Gemini on one key): compatible by default, native by exception
  • Large existing OpenAI codebase: compatible, one base_url change

Where the compatibility layer ends is covered in more depth in the OpenAI-compatible protocol explainer.

Closing

The hard part of a Gemini integration isn't auth, it's knowing which layer you're talking to. The compatible endpoint buys migration speed; the native endpoint buys capability ceiling. Ship on the first, replace the calls that genuinely need multimodality and thinking budgets with the second, and you get both without a rewrite.

New accounts come with trial credit, so both endpoints are testable in a few minutes; after that it's pay-as-you-go with balances that don't expire. Pick two candidate models off the pricing page and A/B them against your own traffic.

Further reading

#gemini api integration#generateContent#gemini native endpoint#openai compatible#gemini api pricing
Get a free API key

Related reading