Text Generation
POST /v1beta/interactions
The Gemini Interactions API generates text output from text input. It uses the Google Gemini Interactions API request and response format.
- Native Gemini Interactions API format
- Plain text input and multi-turn conversations
- Streaming and non-streaming responses
For image, video, audio, and document analysis, see File Analysis.
Route prerequisite
These are Interactions protocol examples. The current local gateway registers Gemini generateContent, not /v1beta/interactions; run these examples only if your deployment separately provides that route. See Gemini CLI for native clients and Nano Banana for image generation. On 404, do not change only the URL: the request and response schemas differ.
Native Text Quick Start
Start here for the standard Tokatlas Gemini route. Choose an enabled Gemini text model from your model list and use it in the request URL. Choose a language below; only the additional Python text-extraction example uses MODEL_ID.
python3 -m pip install requests
export API_KEY='YOUR_TOKATLAS_API_KEY'
export MODEL_ID='YOUR_ENABLED_GEMINI_TEXT_MODEL_ID'See language setup. Set API_KEY and replace model, file URL, and ID placeholders first. Each version displays the raw response to the same request.
curl --fail-with-body --silent --show-error --max-time 180 \
--request POST \
--url "https://api.tokatlas.ai/v1beta/models/YOUR_ENABLED_GEMINI_TEXT_MODEL_ID:generateContent" \
--header "x-goog-api-key: $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Reply with OK only."
}
]
}
]
}'import os
import requests
headers = {
'x-goog-api-key': os.environ["API_KEY"],
'Content-Type': 'application/json',
}
payload = {'contents': [{'role': 'user', 'parts': [{'text': 'Reply with OK only.'}]}]}
response = requests.request(
'POST', 'https://api.tokatlas.ai/v1beta/models/YOUR_ENABLED_GEMINI_TEXT_MODEL_ID:generateContent', headers=headers,
json=payload,
timeout=180,
)
response.raise_for_status()
print(response.text)if (!process.env.API_KEY) throw new Error("Set API_KEY first.");
const response = await fetch("https://api.tokatlas.ai/v1beta/models/YOUR_ENABLED_GEMINI_TEXT_MODEL_ID:generateContent", {
method: "POST",
headers: {
"x-goog-api-key": process.env.API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"contents": [
{
"role": "user",
"parts": [
{
"text": "Reply with OK only."
}
]
}
]
}),
signal: AbortSignal.timeout(180_000),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
console.log(await response.text());import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class Example {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("API_KEY");
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalArgumentException("Set API_KEY first.");
}
String payload = String.join("\n",
"{",
" \"contents\": [",
" {",
" \"role\": \"user\",",
" \"parts\": [",
" {",
" \"text\": \"Reply with OK only.\"",
" }",
" ]",
" }",
" ]",
"}"
);
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30)).build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.tokatlas.ai/v1beta/models/YOUR_ENABLED_GEMINI_TEXT_MODEL_ID:generateContent"))
.timeout(Duration.ofSeconds(180))
.header("x-goog-api-key", apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new IllegalStateException("HTTP " + response.statusCode() + ": "
+ response.body());
}
System.out.println(response.body());
}
}The following Python version additionally extracts text from the response. Save as gemini_text.py and run python3 gemini_text.py:
import os
from urllib.parse import quote
import requests
model = quote(os.environ["MODEL_ID"], safe="")
response = requests.post(
"https://api.tokatlas.ai/v1beta/models/" + model + ":generateContent",
headers={"x-goog-api-key": os.environ["API_KEY"]},
json={"contents": [{"role": "user", "parts": [{"text": "Reply with OK only."}]}]},
timeout=120,
)
response.raise_for_status()
body = response.json()
texts = [part["text"] for candidate in body.get("candidates", [])
for part in candidate.get("content", {}).get("parts", [])
if part.get("text") and not part.get("thought")]
if not texts:
raise RuntimeError(f"No text returned: {body}")
print("\n".join(texts))The remaining sections describe the separate Interactions route where available; do not mix the two request formats.
Endpoint
https://api.tokatlas.ai/v1beta/interactionsStreaming examples use both ?alt=sse and stream: true in the request body; changing the URL alone does not enable streaming.
Authentication
All endpoints require API key authentication. Add your key to the request headers:
x-goog-api-key: YOUR_API_KEY
Content-Type: application/jsonImportant
Never commit a real API key to a repository or expose it in client-side code.
Request Body
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
model | string | Yes | - | Gemini model to use |
input | string, array, or object | Yes | - | User input — plain text, content blocks, or conversation steps |
system_instruction | string | No | - | System prompt to guide model behavior |
generation_config | object | No | - | Generation parameters such as temperature and thinking_level |
previous_interaction_id | string | No | - | ID of the previous interaction for multi-turn conversations |
store | boolean | No | true | Whether to store conversation state server-side |
stream | boolean | No | false | Whether to stream the response via SSE |
model
Current official model IDs checked on 2026-10-03 are listed below. First query your available models, then use the exact ID in model. An upstream release does not imply access through your Tokatlas account.
gemini-3.8-flash— Gemini 3.8 Flashgemini-3.5-flash-lite— Gemini 3.5 Flash-Litegemini-3.1-pro-preview— Gemini 3.1 Pro (preview)
input
The user input for the interaction. For text conversations, use plain text or conversation steps.
Plain text — simplest form for single-turn text generation:
"How does AI work?"Conversation steps — for stateless multi-turn conversations (used with store: false):
[
{
"type": "user_input",
"content": [{"type": "text", "text": "I have 2 dogs in my house."}]
}
]For image, video, audio, and document inputs, see File Analysis.
system_instruction
System prompt to configure the model's behavior, personality, and instructions.
{
"system_instruction": "You are a cat. Your name is Neko.",
"input": "Hello there"
}generation_config
Override default generation parameters.
| Field | Type | Description |
|---|---|---|
temperature | number | Output randomness. Higher values produce more creative output. |
thinking_level | string | Thinking depth: controls cost, latency, and reasoning quality. Common values: "low", "medium", "high". |
Thinking
Gemini models often have thinking enabled by default, allowing the model to reason before responding. Use thinking_level in generation_config to control the trade-off between cost, latency, and intelligence.
Example with thinking level:
{
"model": "gemini-3.7-flash",
"input": "How does AI work?",
"generation_config": {
"thinking_level": "low"
}
}Example with temperature:
{
"model": "gemini-3.7-flash",
"input": "Explain how AI works",
"generation_config": {
"temperature": 1.0
}
}previous_interaction_id
Continue a multi-turn conversation by passing the id from the previous interaction response. The API manages conversation history server-side — you do not need to resend prior turns.
{
"model": "gemini-3.7-flash",
"input": "How many paws are in my house?",
"previous_interaction_id": "INTERACTION_ID_FROM_PREVIOUS_RESPONSE"
}Confirm that the route supports storage and that the prior interaction was created with store: true and is still accessible.
Server-managed conversations
Unlike APIs where you manage conversation history manually, the Interactions API handles conversation state server-side when using previous_interaction_id.
store
Controls whether the interaction is stored server-side for future reference.
true(default) — Server stores the interaction; useprevious_interaction_idto continuefalse— Stateless mode; you must manage and resend the full conversation history ininput
Stateless mode
When using store: false, you must preserve and resend all model-generated steps (including thought and function_call steps) exactly as received, as they contain signatures required to continue the conversation.
stream
Whether to stream the response incrementally via Server-Sent Events.
true— Stream response chunks as they are generatedfalse— Return the complete response at once (default)
Response
| Field | Type | Description |
|---|---|---|
id | string | Unique interaction identifier |
model | string | Model that handled the request |
steps | array | Ordered list of interaction steps (user input, model output, tool calls, etc.) |
status | string | Interaction state, such as completed or requires_action |
Read Text
Select model_output steps and read their text content blocks. Do not assume raw HTTP responses include an SDK’s output_text convenience property. Handle and preserve tool calls and thought steps separately.
steps[]
Each step represents one turn or action in the interaction.
| Field | Type | Description |
|---|---|---|
type | string | Step type: user_input, model_output, thought, function_call, etc. |
content | array | Content for input/output steps; tool steps use their own fields |
Usage Examples
Basic Text Generation
{
"model": "gemini-3.7-flash",
"input": "How does AI work?"
}System Instruction
{
"model": "gemini-3.7-flash",
"system_instruction": "You are a cat. Your name is Neko.",
"input": "Hello there"
}Thinking Configuration
{
"model": "gemini-3.7-flash",
"input": "How does AI work?",
"generation_config": {
"thinking_level": "low"
}
}Stateful Multi-turn Conversation
Turn 1:
{
"model": "gemini-3.7-flash",
"input": "I have 2 dogs in my house."
}Turn 2 (use id from Turn 1 response as previous_interaction_id):
{
"model": "gemini-3.7-flash",
"input": "How many paws are in my house?",
"previous_interaction_id": "INTERACTION_ID_FROM_TURN_1"
}Stateless Multi-turn Conversation
Turn 1:
{
"model": "gemini-3.7-flash",
"store": false,
"input": [
{
"type": "user_input",
"content": [{"type": "text", "text": "I have 2 dogs in my house."}]
}
]
}Build the second turn programmatically. In this fragment, first_response is the parsed first response and first_input is the original input array. Send payload to the same endpoint.
history = [*first_input, *first_response["steps"]]
history.append({
"type": "user_input",
"content": [{"type": "text", "text": "How many paws are in my house?"}],
})
payload = {"model": "gemini-3.7-flash", "store": False, "input": history}Streaming Output
{
"model": "gemini-3.7-flash",
"input": "Explain how AI works",
"stream": true
}Request Examples
See language setup. Set API_KEY and replace model, file URL, and ID placeholders first. Each version displays the raw response to the same request.
curl --fail-with-body --silent --show-error --max-time 180 \
--request POST \
--url "https://api.tokatlas.ai/v1beta/interactions" \
--header "x-goog-api-key: $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "gemini-3.7-flash",
"input": "How does AI work?"
}'import os
import requests
headers = {
'x-goog-api-key': os.environ["API_KEY"],
'Content-Type': 'application/json',
}
payload = {'model': 'gemini-3.7-flash', 'input': 'How does AI work?'}
response = requests.request(
'POST', 'https://api.tokatlas.ai/v1beta/interactions', headers=headers,
json=payload,
timeout=180,
)
response.raise_for_status()
print(response.text)if (!process.env.API_KEY) throw new Error("Set API_KEY first.");
const response = await fetch("https://api.tokatlas.ai/v1beta/interactions", {
method: "POST",
headers: {
"x-goog-api-key": process.env.API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"model": "gemini-3.7-flash",
"input": "How does AI work?"
}),
signal: AbortSignal.timeout(180_000),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
console.log(await response.text());import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class Example {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("API_KEY");
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalArgumentException("Set API_KEY first.");
}
String payload = String.join("\n",
"{",
" \"model\": \"gemini-3.7-flash\",",
" \"input\": \"How does AI work?\"",
"}"
);
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30)).build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.tokatlas.ai/v1beta/interactions"))
.timeout(Duration.ofSeconds(180))
.header("x-goog-api-key", apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new IllegalStateException("HTTP " + response.statusCode() + ": "
+ response.body());
}
System.out.println(response.body());
}
}package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
func main() {
url := "https://api.tokatlas.ai/v1beta/interactions"
payload := map[string]interface{}{
"model": "gemini-3.7-flash",
"input": "How does AI work?",
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("x-goog-api-key", os.Getenv("API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}Streaming Request
See language setup. Set API_KEY and replace model, file URL, and ID placeholders first. Each version displays the raw response to the same request.
curl --fail-with-body --silent --show-error --max-time 180 \
--request POST \
--url "https://api.tokatlas.ai/v1beta/interactions?alt=sse" \
--header "x-goog-api-key: $API_KEY" \
--header "Content-Type: application/json" \
--no-buffer \
--data '{
"model": "gemini-3.7-flash",
"input": "Explain how AI works",
"stream": true
}'import os
import requests
headers = {
'x-goog-api-key': os.environ["API_KEY"],
'Content-Type': 'application/json',
}
payload = {'model': 'gemini-3.7-flash', 'input': 'Explain how AI works', 'stream': True}
response = requests.request(
'POST', 'https://api.tokatlas.ai/v1beta/interactions?alt=sse', headers=headers,
json=payload,
stream=True,
timeout=180,
)
response.raise_for_status()
for line in response.iter_lines():
if line:
print(line.decode("utf-8"), flush=True)if (!process.env.API_KEY) throw new Error("Set API_KEY first.");
const response = await fetch("https://api.tokatlas.ai/v1beta/interactions?alt=sse", {
method: "POST",
headers: {
"x-goog-api-key": process.env.API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"model": "gemini-3.7-flash",
"input": "Explain how AI works",
"stream": true
}),
signal: AbortSignal.timeout(180_000),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
for await (const chunk of response.body) {
process.stdout.write(chunk);
}import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class Example {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("API_KEY");
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalArgumentException("Set API_KEY first.");
}
String payload = String.join("\n",
"{",
" \"model\": \"gemini-3.7-flash\",",
" \"input\": \"Explain how AI works\",",
" \"stream\": true",
"}"
);
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30)).build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.tokatlas.ai/v1beta/interactions?alt=sse"))
.timeout(Duration.ofSeconds(180))
.header("x-goog-api-key", apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<java.io.InputStream> response = client.send(
request, HttpResponse.BodyHandlers.ofInputStream());
try (java.io.InputStream input = response.body()) {
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new IllegalStateException("HTTP " + response.statusCode() + ": "
+ new String(input.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8));
}
input.transferTo(System.out);
}
}
}Multi-turn Request
Run the first request, confirm it succeeded, then use its interaction ID in the second request.
Turn 1: create an interaction
See language setup. Set API_KEY and replace model, file URL, and ID placeholders first. Each version displays the raw response to the same request.
curl --fail-with-body --silent --show-error --max-time 180 \
--request POST \
--url "https://api.tokatlas.ai/v1beta/interactions" \
--header "x-goog-api-key: $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "gemini-3.7-flash",
"store": true,
"input": "I have 2 dogs in my house."
}'import os
import requests
headers = {
'x-goog-api-key': os.environ["API_KEY"],
'Content-Type': 'application/json',
}
payload = {'model': 'gemini-3.7-flash', 'store': True, 'input': 'I have 2 dogs in my house.'}
response = requests.request(
'POST', 'https://api.tokatlas.ai/v1beta/interactions', headers=headers,
json=payload,
timeout=180,
)
response.raise_for_status()
print(response.text)if (!process.env.API_KEY) throw new Error("Set API_KEY first.");
const response = await fetch("https://api.tokatlas.ai/v1beta/interactions", {
method: "POST",
headers: {
"x-goog-api-key": process.env.API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"model": "gemini-3.7-flash",
"store": true,
"input": "I have 2 dogs in my house."
}),
signal: AbortSignal.timeout(180_000),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
console.log(await response.text());import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class Example {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("API_KEY");
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalArgumentException("Set API_KEY first.");
}
String payload = String.join("\n",
"{",
" \"model\": \"gemini-3.7-flash\",",
" \"store\": true,",
" \"input\": \"I have 2 dogs in my house.\"",
"}"
);
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30)).build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.tokatlas.ai/v1beta/interactions"))
.timeout(Duration.ofSeconds(180))
.header("x-goog-api-key", apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new IllegalStateException("HTTP " + response.statusCode() + ": "
+ response.body());
}
System.out.println(response.body());
}
}Turn 2: continue the interaction
Copy the top-level id from the first response into YOUR_PREVIOUS_INTERACTION_ID below, then run the second request. Do not use a step or tool-call ID.
curl --fail-with-body --silent --show-error --max-time 180 \
--request POST \
--url "https://api.tokatlas.ai/v1beta/interactions" \
--header "x-goog-api-key: $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "gemini-3.7-flash",
"store": true,
"previous_interaction_id": "YOUR_PREVIOUS_INTERACTION_ID",
"input": "How many paws are in my house?"
}'import os
import requests
headers = {
'x-goog-api-key': os.environ["API_KEY"],
'Content-Type': 'application/json',
}
payload = {'model': 'gemini-3.7-flash',
'store': True,
'previous_interaction_id': 'YOUR_PREVIOUS_INTERACTION_ID',
'input': 'How many paws are in my house?'}
response = requests.request(
'POST', 'https://api.tokatlas.ai/v1beta/interactions', headers=headers,
json=payload,
timeout=180,
)
response.raise_for_status()
print(response.text)if (!process.env.API_KEY) throw new Error("Set API_KEY first.");
const response = await fetch("https://api.tokatlas.ai/v1beta/interactions", {
method: "POST",
headers: {
"x-goog-api-key": process.env.API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"model": "gemini-3.7-flash",
"store": true,
"previous_interaction_id": "YOUR_PREVIOUS_INTERACTION_ID",
"input": "How many paws are in my house?"
}),
signal: AbortSignal.timeout(180_000),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
console.log(await response.text());import java.net.URI;
import java.net.http.*;
import java.time.Duration;
public class Example {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("API_KEY");
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalArgumentException("Set API_KEY first.");
}
String payload = String.join("\n",
"{",
" \"model\": \"gemini-3.7-flash\",",
" \"store\": true,",
" \"previous_interaction_id\": \"YOUR_PREVIOUS_INTERACTION_ID\",",
" \"input\": \"How many paws are in my house?\"",
"}"
);
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30)).build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.tokatlas.ai/v1beta/interactions"))
.timeout(Duration.ofSeconds(180))
.header("x-goog-api-key", apiKey)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new IllegalStateException("HTTP " + response.statusCode() + ": "
+ response.body());
}
System.out.println(response.body());
}
}Response Example
Non-streaming (stream: false)
{
"id": "interaction_abc123",
"model": "gemini-3.7-flash",
"steps": [
{
"type": "model_output",
"content": [
{
"type": "text",
"text": "Artificial intelligence (AI) refers to computer systems designed to perform tasks that typically require human intelligence..."
}
]
}
],
"status": "completed"
}Streaming (stream: true)
When stream is true, the API returns a Server-Sent Events (SSE) stream. Each event contains a delta with partial text output. Listen for events where event_type is "step.delta" and delta.type is "text".
event: step.delta
data: {"event_type":"step.delta","index":0,"delta":{"type":"text","text":"Artificial"}}
event: step.delta
data: {"event_type":"step.delta","index":0,"delta":{"type":"text","text":" intelligence"}}
event: step.delta
data: {"event_type":"step.delta","index":0,"delta":{"type":"text","text":" (AI) refers to..."}}
event: interaction.completed
data: {"event_type":"interaction.completed","interaction":{"id":"interaction_abc123","model":"gemini-3.7-flash"}}Related Topics
- File Analysis — Upload and analyze documents, images, and other files
- Tool Calling — Function calling and tool use with Gemini models
