Gemini API and SDKs
The Gemini API surface in 2026 is one REST shape with two front doors: the Gemini Developer API (host generativelanguage.googleapis.com, key auth, fast onboarding via AI Studio) and Vertex AI (host aiplatform.googleapis.com, IAM auth, enterprise controls). Both are spoken by the unified google-genai SDK (Python pip install google-genai, JS npm install @google/genai, plus Go / Java / C#) — the same SDK switches mode by constructor argument. The legacy google-generativeai Python package and the original Vertex AI SDK are both being phased out in favor of google-genai; new code should use the unified SDK.
See also
- gemini-models-and-capabilities — model ID catalog the SDK calls into
- vertex-ai-enterprise-gemini — the Vertex AI flavor of this API in detail
- context-caching-gemini —
client.caches.*surface - tool-use-and-function-calling-gemini — tool surface
- claude-api-and-sdks — sister doc for Anthropic
- openai-api-and-sdks — sister doc for OpenAI
1. Client initialization
Developer API (AI Studio key)
from google import genai
client = genai.Client(api_key="GEMINI_API_KEY") # or set env GEMINI_API_KEY / GOOGLE_API_KEYimport { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });Vertex AI (GCP project)
client = genai.Client(
vertexai=True,
project="my-gcp-project",
location="us-central1",
)const ai = new GoogleGenAI({
vertexai: true,
project: "my-gcp-project",
location: "us-central1",
});In Vertex mode the SDK uses Application Default Credentials (ADC). Authenticate with gcloud auth application-default login locally or service-account JSON on servers.
Vertex AI Express Mode
client = genai.Client(vertexai=True, api_key="VERTEX_EXPRESS_KEY")Express keys provide an API-key on-ramp to Vertex without full IAM. Subset of Vertex features.
2. Core method: client.models.generate_content
The canonical entry point for everything except streaming, files, caches, batches, and chats (which have their own resource paths).
response = client.models.generate_content(
model="gemini-3.5-flash", # bare ID — SDK adds models/ prefix
contents="Explain quantum entanglement.", # string OR list of Parts
config=genai.types.GenerateContentConfig(
system_instruction="You are a physics tutor.",
temperature=0.7,
top_p=0.95,
top_k=40,
max_output_tokens=2048,
candidate_count=1, # only 1 supported on most models
stop_sequences=["END"],
response_mime_type="text/plain", # or "application/json"
safety_settings=[...], # see safety section
tools=[...],
tool_config=...,
cached_content="cachedContents/abc123", # reference an explicit cache
thinking_config=genai.types.ThinkingConfig(
thinking_budget=1024, # 2.5 series
# thinking_level="medium", # 3.x series (Gemini 3 only)
include_thoughts=True,
),
),
)
print(response.text)
print(response.usage_metadata.prompt_token_count,
response.usage_metadata.candidates_token_count,
response.usage_metadata.thoughts_token_count,
response.usage_metadata.cached_content_token_count)contents accepts a string, a Content object, or a list mixing Content / Part / strings / PIL images / File references / bytes. The SDK type-routes automatically.
3. Streaming
for chunk in client.models.generate_content_stream(
model="gemini-3.5-flash",
contents="Write a haiku.",
):
print(chunk.text, end="", flush=True)const stream = await ai.models.generateContentStream({
model: "gemini-3.5-flash",
contents: "Write a haiku.",
});
for await (const chunk of stream) {
process.stdout.write(chunk.text ?? "");
}Streaming uses Server-Sent Events under the hood. Each chunk has a partial candidates[].content.parts[].text. Function call parts arrive whole, not partial.
4. Async
The Python SDK exposes async via client.aio:
async def main():
response = await client.aio.models.generate_content(
model="gemini-3.5-flash",
contents="Hello",
)JS / Node SDK is async-native.
5. Multi-turn chat
chat = client.chats.create(model="gemini-3.5-flash")
print(chat.send_message("Hi, my name is Alex.").text)
print(chat.send_message("What's my name?").text)
# History accumulates in chat.historyThe chats helper auto-manages history. Stateful only on the client — server is stateless; every send replays the conversation.
For stateful conversation on the server (Vertex), use the Live API or the new conversation endpoints (limited GA). For most use cases, client-side history replay is fine and supports prompt caching.
6. Multimodal input
from google.genai import types
import pathlib
response = client.models.generate_content(
model="gemini-3.5-flash",
contents=[
"What is in this image?",
types.Part.from_bytes(
data=pathlib.Path("photo.jpg").read_bytes(),
mime_type="image/jpeg",
),
],
)For files larger than ~20 MB or repeated use, upload via Files API first:
myfile = client.files.upload(file="bigvideo.mp4")
response = client.models.generate_content(
model="gemini-3.5-flash",
contents=["Summarize this video.", myfile],
)See vision-and-long-context-gemini for sizing details.
7. Files API
# Upload
f = client.files.upload(file="report.pdf",
config=types.UploadFileConfig(
display_name="Quarterly Report",
mime_type="application/pdf",
))
# List
for f in client.files.list():
print(f.name, f.display_name, f.state)
# Get / delete
f = client.files.get(name=f.name)
client.files.delete(name=f.name)Per ai.google.dev/gemini-api/docs/vision and the file-API docs:
- Files persist for 48 hours before automatic deletion.
- Max file size: 2 GB per file; max 20 GB total per project.
- Files are private to the GCP project / API-key tier and cannot be shared across projects.
8. Caches API
# Create
cache = client.caches.create(
model="models/gemini-3.5-flash",
config=types.CreateCachedContentConfig(
system_instruction="You are a legal-document analyzer.",
contents=[long_document],
ttl="3600s", # 1 hour
# OR expire_time="2026-05-26T00:00:00Z"
),
)
# Use
resp = client.models.generate_content(
model="gemini-3.5-flash",
contents="Summarize Section 3.",
config=types.GenerateContentConfig(cached_content=cache.name),
)
# Manage
caches = list(client.caches.list())
client.caches.update(name=cache.name,
config=types.UpdateCachedContentConfig(ttl="7200s"))
client.caches.delete(name=cache.name)See context-caching-gemini for the cost model.
9. Batch mode
50 % discount, 24-hour SLA (per ai.google.dev/gemini-api/docs/batch-mode).
# JSONL input
batch = client.batches.create(
model="gemini-3.5-flash",
src="files/jsonl-input-file-name", # uploaded JSONL
config=types.CreateBatchJobConfig(
display_name="nightly-summarization",
),
)
# Poll
while batch.state in {"JOB_STATE_PENDING", "JOB_STATE_RUNNING"}:
time.sleep(30)
batch = client.batches.get(name=batch.name)
# Read results
result_file = client.files.download(name=batch.dest.file_name)JSONL input format (one request per line):
{"key": "req-1", "request": {"contents": [{"parts":[{"text":"Hello"}]}]}}
{"key": "req-2", "request": {"contents": [{"parts":[{"text":"World"}]}]}}States: JOB_STATE_PENDING, JOB_STATE_RUNNING, JOB_STATE_SUCCEEDED, JOB_STATE_FAILED, JOB_STATE_CANCELLED, JOB_STATE_EXPIRED (after 48h).
Tip: check batch.dest.failed_request_count — partial failures are common. The output JSONL includes one line per request with either response or error.
For embeddings batching, use client.batches.create_embeddings(...).
10. Embeddings
result = client.models.embed_content(
model="gemini-embedding-2",
contents=["chunk 1 text", "chunk 2 text"],
config=types.EmbedContentConfig(
output_dimensionality=768, # Matryoshka: 128 / 256 / 768 / 1536 / 3072
task_type="RETRIEVAL_DOCUMENT", # only for legacy gemini-embedding-001
),
)
for emb in result.embeddings:
print(len(emb.values))See embeddings-and-vertex-search-gemini for the full model + task-type matrix.
11. Token counting
resp = client.models.count_tokens(
model="gemini-3.5-flash",
contents=long_text,
)
print(resp.total_tokens)count_tokens is free and does not invoke the model — useful for pre-flight cost estimation, especially before caching large content.
12. Function / tool calling (surface)
def get_weather(location: str, unit: str = "celsius") -> dict:
"""Returns current weather for a city."""
return {"temp": 22, "unit": unit, "condition": "sunny"}
resp = client.models.generate_content(
model="gemini-3.5-flash",
contents="What's the weather in Tokyo?",
config=types.GenerateContentConfig(
tools=[get_weather], # SDK auto-introspects signature + docstring
tool_config=types.ToolConfig(
function_calling_config=types.FunctionCallingConfig(mode="AUTO"),
),
),
)
print(resp.text)The Python SDK’s “automatic function calling” feature: pass a Python callable and the SDK both declares it (from signature + type hints + docstring) and executes it on your behalf when the model calls it, then feeds the result back. To disable auto-execution and handle manually:
config=types.GenerateContentConfig(
tools=[get_weather],
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
)See tool-use-and-function-calling-gemini for the full mechanics.
13. Safety settings
Per ai.google.dev/gemini-api/docs/safety-settings:
from google.genai.types import HarmCategory, HarmBlockThreshold
safety_settings = [
types.SafetySetting(
category=HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold=HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
),
types.SafetySetting(
category=HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=HarmBlockThreshold.BLOCK_ONLY_HIGH,
),
]Categories: HARASSMENT, HATE_SPEECH, SEXUALLY_EXPLICIT, DANGEROUS_CONTENT, CIVIC_INTEGRITY. Thresholds: BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE. BLOCK_NONE requires elevated tier on most categories.
When a response is blocked, response.candidates[0].finish_reason == "SAFETY" and response.candidates[0].safety_ratings lists the triggered categories.
14. REST API directly
For non-SDK environments. The base URL pattern:
POST https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash:generateContent
Header: x-goog-api-key: $GEMINI_API_KEY
Content-Type: application/jsonBody shape:
{
"contents": [
{"role": "user", "parts": [{"text": "Hello"}]}
],
"systemInstruction": {"parts": [{"text": "You are concise."}]},
"generationConfig": {
"temperature": 0.7,
"maxOutputTokens": 1024,
"responseMimeType": "application/json",
"responseSchema": {...},
"thinkingConfig": {"thinkingBudget": 1024}
},
"tools": [{"functionDeclarations": [...]}],
"toolConfig": {"functionCallingConfig": {"mode": "AUTO"}},
"safetySettings": [...]
}Streaming variant: :streamGenerateContent (SSE chunks).
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash:generateContent" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"contents":[{"role":"user","parts":[{"text":"Explain caching"}]}]}'15. Response shape
{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{"text": "..."},
{"functionCall": {"name": "...", "args": {...}, "id": "fc_abc"}},
{"executableCode": {"language": "PYTHON", "code": "..."}},
{"codeExecutionResult": {"outcome": "OUTCOME_OK", "output": "..."}},
{"thought": true, "text": "summary of reasoning"}
]
},
"finishReason": "STOP",
"safetyRatings": [...],
"groundingMetadata": {...},
"citationMetadata": {...}
}
],
"usageMetadata": {
"promptTokenCount": 50,
"candidatesTokenCount": 200,
"thoughtsTokenCount": 800,
"cachedContentTokenCount": 5000,
"totalTokenCount": 1050
}
}finishReason values: STOP, MAX_TOKENS, SAFETY, RECITATION (output matched training data too closely), OTHER, BLOCKLIST, PROHIBITED_CONTENT, SPII, MALFORMED_FUNCTION_CALL.
16. Error model
Common HTTP errors:
- 400 INVALID_ARGUMENT — schema violation, bad model ID, exceeded context, malformed content
- 401 / 403 PERMISSION_DENIED — API key missing / wrong / project missing API
- 404 NOT_FOUND — model ID typo, file not found
- 429 RESOURCE_EXHAUSTED — rate-limit or quota
- 500 INTERNAL — backend; retry with exponential backoff
- 503 UNAVAILABLE — backend overloaded; retry
The SDK retries 429 / 5xx with exponential backoff by default. Use http_options=types.HttpOptions(timeout=30.0) or client.options.retry to tune.
17. Rate limits
Per ai.google.dev/gemini-api/docs/rate-limits. Three free tier + four paid tiers. Limits are per-model and per-tier on:
- RPM (requests per minute)
- TPM (tokens per minute)
- RPD (requests per day)
Paid Tier 1 typically gives 1,000 RPM / 1M TPM / 1.5M RPD on Gemini Flash models. Tier 2 / 3 / 4 unlock larger limits with spend thresholds. Vertex AI uses different per-region quotas; check the GCP console.
18. SDK versioning + API versions
The unified SDK defaults to v1beta API endpoints — covering all current features. Pin to stable v1:
client = genai.Client(
api_key="...",
http_options=types.HttpOptions(api_version="v1"),
)v1 is missing some features (thinking, caching, code-execution tool, some batch modes). Use v1beta for production unless you have a strict stability requirement and don’t need those features.
19. Migrating from google-generativeai (legacy SDK)
The pre-2025 Python SDK was google-generativeai. Migration to google-genai:
| Legacy | New |
|---|---|
import google.generativeai as genai | from google import genai |
genai.configure(api_key=...) | client = genai.Client(api_key=...) |
model = genai.GenerativeModel("gemini-1.5-flash") | (no model object — use client.models.generate_content(model="...")) |
model.generate_content("...") | client.models.generate_content(model="...", contents="...") |
model.start_chat() | client.chats.create(model="...") |
genai.upload_file("...") | client.files.upload(file="...") |
model.count_tokens("...") | client.models.count_tokens(model="...", contents="...") |
The legacy SDK is in maintenance mode; new features (Files API improvements, structured caches, batch v2) ship only on google-genai.
20. Further reading
- API quickstart — minimal hello-world per language
- API overview — methods, params, response shape
- google-genai Python SDK — source + reference
- @google/genai (JS) — JS SDK source
- google-gemini/cookbook — recipe-style worked examples
- Rate limits — tier ↔ RPM/TPM/RPD table
- Safety settings — full HarmCategory / HarmBlockThreshold matrix