GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20
Articles/API / SDK
API / SDK/2026-04-11Intermediate

Gemini 3.1 Pro REST API Getting Started Guide — generativelanguage.googleapis.com in Practice

A complete guide to calling the Gemini 3.1 Pro generativelanguage.googleapis.com REST API using curl, Python, and JavaScript — covering authentication, streaming, multi-turn chat, and common errors.

gemini-api277rest-api2gemini-3.1-progenerativelanguage3python104javascript3curl

With the release of Gemini 3.1 Pro, the generativelanguage.googleapis.com endpoint has received significant updates. Calling the REST API directly — without the SDK — is useful in many real-world situations: serverless environments, lightweight scripts, or any context where you need language-agnostic integration.


1. Model Name and Endpoint

When making REST API calls to Gemini 3.1 Pro, use one of these model identifiers:

  • Stable: gemini-3.1-pro
  • Latest alias: gemini-3.1-pro-latest (always points to the most recent minor version)
  • Preview: gemini-3.1-pro-exp

The base URL remains the same:

POST https://generativelanguage.googleapis.com/v1beta/models/{model-name}:generateContent

As of April 2026, v1beta remains the de-facto main API version, giving access to Gemini's latest features including thinking, Function Calling, and multimodal input. While v1 is more stable, it may not yet support the newest model capabilities, so v1beta is recommended during development.


2. Getting Your API Key and Authenticating

API Key (for personal projects and prototypes)

Visit Google AI Studio and click Create API key. Store your key as an environment variable — never hard-code it in source files.

export GEMINI_API_KEY="YOUR_GEMINI_API_KEY"

Pass the key via query parameter or the x-goog-api-key header:

# Query parameter
POST .../generateContent?key=${GEMINI_API_KEY}
 
# Header (recommended)
-H "x-goog-api-key: ${GEMINI_API_KEY}"

OAuth / Service Account (for production)

In production, use Google service account credentials instead of an API key. An OAuth 2.0 access token works with the generativelanguage.googleapis.com endpoint as a Bearer token:

ACCESS_TOKEN=$(gcloud auth print-access-token)
# or
ACCESS_TOKEN=$(gcloud auth application-default print-access-token)

3. Your First Request with curl

Here is the simplest possible text generation request:

curl -s -X POST \
  "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-pro:generateContent" \
  -H "x-goog-api-key: ${GEMINI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [
      {
        "parts": [{"text": "Explain Python list comprehensions in 3 sentences."}]
      }
    ]
  }'

The response is JSON:

{
  "candidates": [
    {
      "content": {
        "parts": [{"text": "List comprehensions provide a concise way..."}],
        "role": "model"
      },
      "finishReason": "STOP",
      "index": 0
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 14,
    "candidatesTokenCount": 138,
    "totalTokenCount": 152
  }
}

The generated text lives at candidates[0].content.parts[0].text. Use usageMetadata to monitor token consumption for cost management.


4. Text Generation with Python requests

import os
import requests
 
API_KEY = os.environ.get("GEMINI_API_KEY")
BASE_URL = "https://generativelanguage.googleapis.com/v1beta"
MODEL = "gemini-3.1-pro"
 
def generate_text(prompt: str, system_instruction: str = None) -> str:
    """Generate text with Gemini 3.1 Pro via REST API."""
    url = f"{BASE_URL}/models/{MODEL}:generateContent"
    headers = {
        "x-goog-api-key": API_KEY,
        "Content-Type": "application/json",
    }
 
    payload = {
        "contents": [
            {"role": "user", "parts": [{"text": prompt}]}
        ],
        "generationConfig": {
            "temperature": 0.7,
            "topP": 0.95,
            "maxOutputTokens": 2048,
        },
    }
 
    # Optional system instruction
    if system_instruction:
        payload["systemInstruction"] = {
            "parts": [{"text": system_instruction}]
        }
 
    response = requests.post(url, headers=headers, json=payload, timeout=60)
    response.raise_for_status()
 
    data = response.json()
    return data["candidates"][0]["content"]["parts"][0]["text"]
 
if __name__ == "__main__":
    result = generate_text(
        prompt="What are the main differences between FastAPI and Django?",
        system_instruction=(
            "You are a senior backend engineer. "
            "Explain concepts accurately but in a way beginners can follow."
        )
    )
    print(result)
    # Expected output:
    # FastAPI is an ASGI-based micro-framework that leverages Python type hints
    # for automatic API documentation, while Django is a full-featured MVC framework...

5. Multi-Turn Chat (Managing Conversation History)

With the REST API, you maintain conversation history on the client side and send it with each request:

import os
import requests
 
API_KEY = os.environ.get("GEMINI_API_KEY")
BASE_URL = "https://generativelanguage.googleapis.com/v1beta"
MODEL = "gemini-3.1-pro"
 
class GeminiChat:
    """Multi-turn chat with automatic history management."""
 
    def __init__(self, system_instruction: str = None):
        self.history = []
        self.system_instruction = system_instruction
        self.url = f"{BASE_URL}/models/{MODEL}:generateContent"
        self.headers = {
            "x-goog-api-key": API_KEY,
            "Content-Type": "application/json",
        }
 
    def send_message(self, user_message: str) -> str:
        # Append user message to history
        self.history.append({
            "role": "user",
            "parts": [{"text": user_message}]
        })
 
        payload = {"contents": self.history}
        if self.system_instruction:
            payload["systemInstruction"] = {
                "parts": [{"text": self.system_instruction}]
            }
 
        response = requests.post(
            self.url, headers=self.headers, json=payload, timeout=60
        )
        response.raise_for_status()
        data = response.json()
 
        model_reply = data["candidates"][0]["content"]["parts"][0]["text"]
 
        # Append model reply to history for next turn
        self.history.append({
            "role": "model",
            "parts": [{"text": model_reply}]
        })
 
        return model_reply
 
# Example usage
chat = GeminiChat(system_instruction="You are a Python tutor.")
print(chat.send_message("Explain type casting in Python"))
print(chat.send_message("What is the difference between int and float?"))
# Expected output:
# Type casting in Python uses built-in functions like int(), float(), str()...
# The int type stores whole numbers without a decimal point, while float...

6. Streaming Responses

Improve perceived performance on long answers with streaming mode:

import os
import requests
import json
 
API_KEY = os.environ.get("GEMINI_API_KEY")
BASE_URL = "https://generativelanguage.googleapis.com/v1beta"
MODEL = "gemini-3.1-pro"
 
def stream_generate(prompt: str):
    """Stream text generation, printing chunks as they arrive."""
    url = f"{BASE_URL}/models/{MODEL}:streamGenerateContent?alt=sse"
    headers = {
        "x-goog-api-key": API_KEY,
        "Content-Type": "application/json",
    }
    payload = {
        "contents": [{"role": "user", "parts": [{"text": prompt}]}],
        "generationConfig": {"maxOutputTokens": 4096},
    }
 
    with requests.post(url, headers=headers, json=payload,
                       stream=True, timeout=120) as response:
        response.raise_for_status()
        for line in response.iter_lines():
            if line and line.startswith(b"data: "):
                data_str = line[6:].decode("utf-8")
                if data_str == "[DONE]":
                    break
                try:
                    chunk = json.loads(data_str)
                    parts = chunk.get("candidates", [{}])[0].get(
                        "content", {}).get("parts", [])
                    for part in parts:
                        if "text" in part:
                            print(part["text"], end="", flush=True)
                except json.JSONDecodeError:
                    pass
    print()  # Final newline
 
if __name__ == "__main__":
    stream_generate("Walk me through building a simple web scraper in Python.")
    # Expected behavior:
    # Text appears in real time as SSE chunks stream in

Use streamGenerateContent with ?alt=sse to receive Server-Sent Events.


7. JavaScript / fetch

Access the API from Node.js or Deno with the native fetch API:

const API_KEY = process.env.GEMINI_API_KEY;
const MODEL = "gemini-3.1-pro";
const BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
 
async function generateContent(prompt) {
  const url = `${BASE_URL}/models/${MODEL}:generateContent`;
 
  const response = await fetch(url, {
    method: "POST",
    headers: {
      "x-goog-api-key": API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      contents: [{ role: "user", parts: [{ text: prompt }] }],
      generationConfig: {
        temperature: 0.8,
        maxOutputTokens: 1024,
      },
    }),
  });
 
  if (\!response.ok) {
    const error = await response.json();
    throw new Error(`API Error ${response.status}: ${JSON.stringify(error)}`);
  }
 
  const data = await response.json();
  return data.candidates[0].content.parts[0].text;
}
 
// Example usage
generateContent("What are TypeScript type guards?")
  .then(console.log)
  .catch(console.error);
// Expected output:
// Type guards in TypeScript are expressions that narrow the type of a variable...

8. Common Errors and Fixes

400 Bad Request — INVALID_ARGUMENT

Usually caused by an incorrect contents array structure. The role field must be "user" or "model" only — "system" is not a valid role. Use the systemInstruction top-level field for system prompts.

403 Forbidden — API key not valid

Either the key is wrong, or the Generative Language API has not been enabled for your Google Cloud project. Enable it in Google Cloud Console.

429 Resource Exhausted — RATE_LIMIT_EXCEEDED

The free tier has per-minute request limits. Implement exponential backoff for retries, or upgrade to a paid plan:

import time
 
def generate_with_retry(prompt, max_retries=3):
    for attempt in range(max_retries):
        try:
            return generate_text(prompt)
        except requests.HTTPError as e:
            if e.response.status_code == 429:
                wait_time = 2 ** attempt  # 1, 2, 4 seconds
                print(f"Rate limit hit. Retrying in {wait_time}s...")
                time.sleep(wait_time)
            else:
                raise
    raise Exception("Max retries exceeded")

500 Internal Server Error

A temporary server-side issue. Wait a few seconds and retry.


9. Controlling Output with generationConfig

"generationConfig": {
  "temperature": 0.7,          // 0.0-2.0 (lower = more deterministic)
  "topP": 0.95,                // nucleus sampling
  "topK": 40,                  // top-k sampling
  "maxOutputTokens": 8192,     // max tokens in the response
  "stopSequences": ["---"],    // stop generation at this string
  "candidateCount": 1,         // number of candidates (default 1)
  "responseMimeType": "application/json"  // force JSON output
}

Setting responseMimeType: "application/json" instructs Gemini to return a properly formatted JSON response. Combine it with response_schema for strict schema enforcement.


Looking back

The Gemini 3.1 Pro REST API lets you integrate powerful AI capabilities into virtually any application — no SDK required. Here is a quick recap:

  • Endpoint: https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-pro:generateContent
  • Authentication: the x-goog-api-key header is the simplest approach
  • Conversation history: managed on the client side as the contents array
  • Streaming: use streamGenerateContent?alt=sse
  • Rate limits: handle 429 errors with exponential backoff

Ready to go further? The Gemini 3.1 Pro Custom Tools Agent Guide covers advanced use cases including Function Calling and agent workflows with full code examples.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

API / SDK2026-05-01
Why 'contents must alternate between user and model' Won't Go Away in the Gemini API — and How to Fix It
A focused guide to the Gemini API's 'contents must alternate between user and model' error — what really triggers it, why role names from OpenAI break it, and how to fix Function Calling and system_instruction pitfalls with copy-pasteable code.
API / SDK2026-07-15
Sample what you already accepted — an audit budget that catches silent quality drift
A confidence gate only ever looks at output the model hesitated on. Silent drift sinks into the batch that sailed through. Working from a fixed 30-minutes-a-day review budget, this walks through deriving detection time from the binomial, reallocating the same budget across risk strata, and catching slow decay with a cumulative monitor.
API / SDK2026-07-14
When Gemini's executed result and its prose disagree on a number — a gate that trusts only code_execution_result
Gemini Code Execution returns the value it actually computed and the sentence describing it as separate parts. Trust the prose and you can inherit a hallucinated number. Here is a verification gate, in working code, that extracts the executed result as the single source of truth and rejects prose that disagrees.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →