# Gemini models.generateContent — exhaustive reference
Status: DOCUMENTED + LIVE_VERIFIED (190-call probe on gemini-3.5-flash-lite / gemini-3.5-flash / gemini-3.8-flash, 2026-09-18, est. $0.0045, free-tier key; raws in tmp-live/gemini-core/). Explicit caching and gemini-3.1-pro-preview probes are ACCOUNT_RESTRICTED on this key.
Sources: https://ai.google.dev/api/generate-content · https://ai.google.dev/gemini-api/docs/generate-content/text-generation · https://ai.google.dev/gemini-api/docs/generate-content/gemini-3 · https://ai.google.dev/gemini-api/docs/generate-content/whats-new-gemini-3.5 · https://ai.google.dev/gemini-api/docs/api-versions · discovery https://generativelanguage.googleapis.com/$discovery/rest?version=v1beta (rev. 20260918)
Machine-readable: generated/fragments/endpoints/gemini-core.json, generated/fragments/parameters/gemini-generate-content.json (68 records), generated/fragments/objects/gemini-core-objects.json, generated/fragments/streaming-events/gemini-core.json, generated/fragments/compatibility/gemini-feature-model-matrix.json
Last verified: 2026-09-18
# 1. Request
POST https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent
x-goog-api-key: <key> (never put the key in the URL; `?key=` works but leaks)
Content-Type: application/json
- Also:
/v1/models/{model}:generateContent (stable; identical shape, verified), tunedModels/{id}:generateContent (tuning domain), dynamic/{id}:generateContent (discovery only — both probed ids → 404, purpose unknown).
- Field names: camelCase and snake_case are interchangeable on the wire (
system_instruction, generation_config.max_output_tokens verified).
- Unknown fields →
400 INVALID_ARGUMENT "Invalid JSON payload received. Unknown name \"x\" at 'generation_config': Cannot find field." with a google.rpc.BadRequest.fieldViolations detail.
- Method must be POST:
GET …:generateContent → 404 with an empty body.
# 1.1 Body (GenerateContentRequest)
| Field |
Type |
Required |
Notes (live) |
contents[] |
Content |
yes |
Ordered turns. A single bare Content object (not array) is accepted. Missing → 400 * GenerateContentRequest.contents: contents is not specified. Last turn must be user (400 Requests ending with a model turn are not supported.). Empty parts → 400 Request has empty input. |
contents[].role |
user | model |
no |
Omitted = user. assistant/system are not roles. |
contents[].parts[] |
Part |
yes |
Exactly one data field per part (text, inlineData, fileData, functionCall, functionResponse, executableCode, codeExecutionResult, toolCall, toolResponse) + metadata (thought, thoughtSignature, videoMetadata, mediaResolution, mediaProcessing, partMetadata). See §1.2. |
systemInstruction |
Content |
no |
Text only; role ignored. Counted in promptTokenCount. |
tools[], toolConfig |
Tool / ToolConfig |
no |
Shape only here — see tools docs. Declarations are billed as prompt tokens. |
safetySettings[] |
SafetySetting |
no |
See docs/gemini/safety.md. |
generationConfig |
GenerationConfig |
no |
§1.3. |
cachedContent |
string |
no |
cachedContents/{id} — see docs/gemini/context-caching.md. |
serviceTier |
standard | flex | priority | unspecified |
no |
Echoed in usageMetadata.serviceTier. flex accepted live (0.7 s, tier echoed flex). Invalid → 400 Invalid value at 'service_tier' … "turbo". |
labels |
map |
no |
Cloud-label rules (key starts with a letter, ≤ 63 chars, [a-z0-9_-]). Documented key safety_identifier. Accepted live, not echoed. |
store |
boolean |
no |
Per-request logging override (discovery). Accepted live. |
# 1.2 Parts
| Part field |
Shape |
Live |
text |
string |
— |
inlineData |
{mimeType, data (base64), displayName?} |
1×1 PNG → 1089 IMAGE tokens on Gemini 3.5; 1-page PDF → 520 IMAGE tokens; text/plain bytes are read as text; declared MIME is not validated against bytes (PNG sent as image/bmp → 200). Payload cap 20 MB (image/audio/video guides) — use Files above. |
fileData |
{fileUri, mimeType?, displayName?} |
files/… URI from the Files API (mimeType optional — taken from the File), public YouTube URL, or public/pre-signed HTTPS media URL (≤ 100 MB, fetched per request — 8 s for a 1080-token JPEG). Deleted/unknown file → 403 PERMISSION_DENIED You do not have permission to access the File <id> or it may not exist. |
functionCall / functionResponse |
{name, args, id} / {name, response, id, parts[], scheduling, willContinue} |
tools domain |
executableCode / codeExecutionResult |
{language, code, id} / {outcome, output, id} |
tools domain |
toolCall / toolResponse |
server-side built-in tool echoes |
discovery (toolConfig.includeServerSideToolInvocations) |
thought |
boolean |
thought-summary parts (output) |
thoughtSignature |
base64 |
Present on the last part of every Gemini 3 response (even plain OK). Echo it back unchanged. Tampered → 400 Corrupted thought signature.; dummy skip_thought_signature_validator accepted. See docs/gemini/thinking.md. |
videoMetadata |
{startOffset, endOffset, fps} |
clip/sample video (static mode). 10 s of a YouTube video: VIDEO 710 + AUDIO 320 tokens vs 10650 + 4777 for the whole clip. |
mediaResolution |
{level: MEDIA_RESOLUTION_LOW|MEDIUM|HIGH|ULTRA_HIGH} |
per-part (Gemini 3). 1×1 PNG: LOW 256, MEDIUM 529, HIGH/default 1089, ULTRA_HIGH 2209 tokens. |
mediaProcessing |
STATIC | AGENTIC |
video only (agentic on 3.8/3.7/3.6 Flash, 3.5 Flash-Lite) — not probed |
partMetadata |
Struct |
discovery only |
# 1.3 generationConfig — every field
| Field |
Type / range |
Default (models.get flash-lite) |
Live result on gemini-3.5-flash-lite |
temperature |
float [0.0, 2.0] |
1.0 (maxTemperature 2) |
2.5 → 400 temperature must be in the range [0.0, 2.0]. Gemini 3.x: keep 1.0. |
topP |
float |
0.95 |
accepted |
topK |
int |
64 |
accepted (models without topK in models.get reject it) |
candidateCount |
int |
1 |
2 → 400 Multiple candidates is not enabled for this model (all Gemini 3.x) |
maxOutputTokens |
int ≤ outputTokenLimit (65536) |
model limit |
Includes thinking tokens. Hit → finishReason: MAX_TOKENS; with dynamic thinking + 64 the answer was empty (60 thought tokens). |
stopSequences[] |
≤ 5 strings |
— |
6 → 400 the number of stop_sequences must not exceed 5. |
presencePenalty, frequencyPenalty |
float |
— |
400 Penalty is not enabled for this model |
seed |
int32 |
random |
seed 7 twice → identical Capybara |
responseLogprobs, logprobs (0–20) |
bool, int |
— |
400 Logprobs is not enabled for this model |
responseMimeType |
text/plain | application/json | application/xml | application/yaml | text/x.enum |
text/plain |
other → 400 allowed mimetypes are … (verbatim list). XML verified. |
responseSchema |
OpenAPI Schema subset (deprecated) |
— |
works with propertyOrdering; ignored without responseMimeType; non-Schema keys (additionalProperties) → 400 |
responseJsonSchema |
JSON Schema (deprecated in discovery) |
— |
works, even without responseMimeType (not enforced); $defs/$ref/anyOf/null OK |
responseFormat |
{text:{mimeType: APPLICATION_JSON|TEXT_PLAIN, schema}, audio:{…}, image:{…}} |
— |
new canonical form; wire enum is uppercase ("application/json" → 400 invalid enum; the docs' lowercase form is SDK-mapped) |
responseModalities[] |
TEXT | IMAGE | AUDIO |
[TEXT] |
[TEXT, IMAGE] on a text model → 200 text only (no error) |
speechConfig |
voice/multi-speaker/languageCode |
— |
ignored on text model (200) — media domain |
imageConfig |
{aspectRatio, imageSize} |
— |
400 Aspect ratio is not enabled for this model on text model — media domain |
mediaResolution |
MEDIA_RESOLUTION_LOW|MEDIUM|HIGH (global) |
model default |
LOW → PNG 256 tokens; ULTRA_HIGH globally → 400 invalid enum (per-part only) |
thinkingConfig |
{thinkingLevel, thinkingBudget, includeThoughts} |
model default |
both level+budget → 400 You can only set only one of thinking budget and thinking level. See thinking.md |
audioTimestamp |
(SDK only) |
— |
400 Unknown name "audioTimestamp" — not a Gemini API field |
enableEnhancedCivicAnswers |
bool |
— |
200 |
enableAffectiveDialog |
bool |
— |
Live-API models (discovery) |
audioTranscriptionConfig, translationConfig |
objects |
— |
transcription/Live models — media domain |
modelSelectionConfig, routingConfig, modelArmorConfig |
SDK |
— |
Vertex-only; absent from the Gemini discovery |
# 2. Response (GenerateContentResponse)
{
"candidates": [{"content": {"parts": [{"text": "OK", "thoughtSignature": "El4KXAFpFH0T…"}], "role": "model"}, "finishReason": "STOP", "index": 0}],
"usageMetadata": {"promptTokenCount": 5, "candidatesTokenCount": 1, "totalTokenCount": 6,
"promptTokensDetails": [{"modality": "TEXT", "tokenCount": 5}], "serviceTier": "standard"},
"modelVersion": "gemini-3.5-flash-lite",
"responseId": "ZgWuapkcpuD-4w_B5sz4CQ"
}
candidates[] — absent only when the prompt is blocked (promptFeedback.blockReason). Each: content, finishReason, finishMessage?, index, safetyRatings? (only when safetySettings were sent), citationMetadata?, groundingMetadata?, urlContextMetadata?, logprobsResult?, avgLogprobs?, tokenCount?.
finishReason enum (discovery 20260918): STOP, MAX_TOKENS, SAFETY, RECITATION, LANGUAGE, OTHER, BLOCKLIST, PROHIBITED_CONTENT, SPII, MALFORMED_FUNCTION_CALL, IMAGE_SAFETY, IMAGE_PROHIBITED_CONTENT, IMAGE_OTHER, NO_IMAGE, IMAGE_RECITATION, UNEXPECTED_TOOL_CALL, TOO_MANY_TOOL_CALLS, MISSING_THOUGHT_SIGNATURE, MALFORMED_RESPONSE, ESCALATION, PUP_LIMITED_DISABLED.
usageMetadata: promptTokenCount (includes cached tokens), cachedContentTokenCount, candidatesTokenCount (absent when only thoughts were produced), thoughtsTokenCount, toolUsePromptTokenCount, totalTokenCount, promptTokensDetails[]/cacheTokensDetails[]/candidatesTokensDetails[]/toolUsePromptTokensDetails[] ({modality: TEXT|IMAGE|VIDEO|AUDIO|DOCUMENT, tokenCount}), serviceTier (observed on every 200: standard, flex when requested).
modelVersion = model id (gemini-3.5-flash-lite), while models.get(...).version is 3.5-flash-lite-07-2026. responseId opaque. modelStatus ({modelStage, retirementTime, message}) documented in discovery, never observed.
- No rate-limit or request-id headers are returned (only
Server-Timing: gfet4t7; dur=…).
# 3. Errors (observed)
| HTTP |
error.status |
Trigger |
Message (verbatim, trimmed) |
| 400 |
INVALID_ARGUMENT |
validation |
* GenerateContentRequest.<field>: … or Invalid JSON payload received. Unknown name "…" or Invalid value at '<field>' (type.googleapis.com/…Enum), "value" |
| 400 |
INVALID_ARGUMENT |
malformed JSON |
Invalid JSON payload received. Unexpected end of string. Expected a value or ] within an array. |
| 400 |
FAILED_PRECONDITION |
billing-gated feature (async batch) |
Precondition check failed. |
| 403 |
PERMISSION_DENIED |
deleted/unknown File |
You do not have permission to access the File <id> or it may not exist. |
| 404 |
NOT_FOUND |
unknown model / unsupported method |
models/<id> is not found for API version v1beta, or is not supported for generateContent. Call ModelService.ListModels … |
| 429 |
RESOURCE_EXHAUSTED |
free-tier RPM (15/min/model on flash-lite) |
… Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_requests, limit: 15 … + QuotaFailure + RetryInfo.retryDelay |
| 429 |
RESOURCE_EXHAUSTED |
caching on free tier |
TotalCachedContentStorageTokensPerModelFreeTier limit exceeded for model gemini-3.5-flash: limit=0, requested=5301 |
| 501 |
UNIMPLEMENTED |
PaLM methods |
Operation is not implemented, or supported, or enabled. |
Envelope: {"error": {"code": <http>, "message": "...", "status": "<google.rpc.Code>", "details": [...]}}.
# 4. SDK mapping
- Python
google-genai 2.24: client.models.generate_content(model=, contents=, config=types.GenerateContentConfig(system_instruction=, temperature=, max_output_tokens=, response_mime_type=, response_json_schema=, thinking_config=, safety_settings=, cached_content=, labels=, service_tier=, http_options=types.HttpOptions(api_version=, timeout=, headers=, base_url=, retry_options=))). http_options is client-side only (not on the wire). response.text concatenates non-thought text parts.
- Node
@google/genai 2.23: ai.models.generateContent({model, contents, config}) — same config keys in camelCase.
- Known SDK-vs-REST gaps (verified): both SDKs refuse
system_instruction/tools in count_tokens for the Developer API ("only supported in Gemini Enterprise Agent Platform mode") although REST accepts them via generateContentRequest; SDK-only config fields (audio_timestamp, model_selection_config, routing_config, model_armor_config, SafetySetting.method) are Vertex-only and rejected on the wire (Unknown name).
- REST examples:
examples/gemini/generate-content/.
# 5. Related pages
docs/gemini/streaming.md · structured-outputs.md · thinking.md · safety.md · context-caching.md · files.md · multimodal-input.md · token-counting.md · embeddings.md · legacy-palm-methods.md