> ## AI Agent Context
> Get the complete documentation index at: https://aistudio.google.com/docs/llms.txt
> Use this file to discover all available pages.
> For the full documentation in a single file, fetch: https://aistudio.google.com/docs/llms-full.txt
# Interactions API: Breaking changes migration guide (May 2026)
{% callout type="warning" %}
**Breaking changes**: The changes described in this guide are
breaking changes to the Interactions API. The legacy schema will be
removed on **June 8, 2026**. Use the
`Api-Revision` request header to
[manage your migration](/docs/interactions-breaking-changes-may-2026#how-to-migrate).
{% /callout %}
The `v1beta` Interactions API is introducing breaking changes that restructure the
API shape to support future capabilities like mid-flight steering and
asynchronous tool calls. This page explains what's changing and provides
before-and-after code examples to help you migrate. There are two categories
of changes:
1. [**Steps schema**](/docs/interactions-breaking-changes-may-2026#steps-schema): A new `steps` array replaces the
`outputs` array, providing a structured timeline of each interaction turn.
2. [**Output format configuration**](/docs/interactions-breaking-changes-may-2026#output-format-config): A new polymorphic
`response_format` consolidates all output format controls and removes
`response_mime_type`.
Follow the steps in [How to migrate to the new schema](/docs/interactions-breaking-changes-may-2026#how-to-migrate) to
update your integration.
## Core change: `outputs` to `steps` {% id="steps-schema" %}
The new schema replaces the `outputs` array with a `steps` array.
- **Legacy**: Responses returned a flat `outputs` array containing only the model's generated content.
- **New schema**: Responses return a `steps` array containing structured steps with type discriminators.
`POST /interactions` returns only output steps. `GET /interactions/{id}`
returns the full step timeline, including the initial `user_input` step.
### Basic input/output (unary) {% id="basic-unary" %}
#### Before (legacy)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
# Request
interaction = client.interactions.create(
model="gemini-3.8-flash", input="Tell me a joke."
)
# Response access
print(interaction.outputs[-1].text)
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
// Request
const interaction = await client.interactions.create({
model: 'gemini-3.8-flash',
input: 'Tell me a joke.'
});
// Response access
console.log(interaction.outputs[-1].text);
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.8-flash",
"input": "Tell me a joke."
}'
```
```none
// Response
{
"id": "int_123",
"role": "model",
{{ '' }}"outputs": [
{
"type": "text",
"text": "Why did the chicken cross the road?"
}
]{{ '' }}
}
```
{% /tab %}
{% /tabs %}
#### After (new schema)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
# Request
interaction = client.interactions.create(
model="gemini-3.8-flash", input="Tell me a joke."
)
# Response access (Recommended sugar)
print(interaction.output_text)
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
// Request
const interaction = await client.interactions.create({
model: 'gemini-3.8-flash',
input: 'Tell me a joke.'
});
// Response access (Recommended sugar)
console.log(interaction.output_text);
```
Note: For details on SDK convenience properties (including `.output_text`,
`.output_image`, and `.output_audio`), see
[Access outputs with SDK convenience properties](/docs/interactions-overview#sdk-sugar)
in the overview.
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
# Opt-in needed before May 26th
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
{{ '**' }}-H "Api-Revision: 2026-05-20" \{{ '**' }}
-d '{
"model": "gemini-3.8-flash",
"input": "Tell me a joke."
}'
```
```html
// POST Response
{
"id": "int_123",
{{ '' }}"steps": [
{
"type": "model_output",
"content": [
{
"type": "text",
"text": "Why did the chicken cross the road?"
}
]
}
]{{ '' }}
}
// GET /v1beta/interactions/int_123 (returns full timeline including input)
{
"id": "int_123",
"steps": [
{
"type": "user_input",
"content": [
{ "type": "text", "text": "Tell me a joke." }
]
},
{
"type": "model_output",
"content": [
{
"type": "text",
"text": "Why did the chicken cross the road?"
}
]
}
]
}
```
{% /tab %}
{% /tabs %}
### Function calling {% id="function-calling" %}
The request structure remains unchanged, but the response replaces the flat
`outputs` content with structured steps.
#### Before (legacy)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
# Accessing function call in legacy schema
for output in interaction.outputs:
if output.type == "function_call":
print(f"Calling {output.name} with {output.arguments}")
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
// Accessing function call in legacy schema
for (const output of interaction.outputs) {
if (output.type === 'function_call') {
console.log(`Calling ${output.name} with ${JSON.stringify(output.arguments)}`);
}
}
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```json
// Response
{
"id": "int_001",
"role": "model",
"status": "requires_action",
{{ '' }}"outputs": [
{
"type": "thought",
"signature": "abc123..."
},
{
"type": "function_call",
"id": "fc_1",
"name": "get_weather",
"arguments": { "location": "Boston, MA" }
}
]{{ '' }}
}
```
{% /tab %}
{% /tabs %}
#### After (new schema)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
# Accessing function call in new steps schema
for step in interaction.steps:
if step.type == "function_call":
print(f"Calling {step.name} with {step.arguments}")
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
// Accessing function call in new steps schema
for (const step of interaction.steps) {
if (step.type === 'function_call') {
console.log(`Calling ${step.name} with ${JSON.stringify(step.arguments)}`);
}
}
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```json
// POST Response
{
"id": "int_001",
"status": "requires_action",
{{ '' }}"steps": [
{
"type": "thought",
"summary": [{
"type": "text",
"text": "I need to check the weather in Boston..."
}],
"signature": "abc123..."
},
{
"type": "function_call",
"id": "fc_1",
"name": "get_weather",
"arguments": { "location": "Boston, MA" }
}
]{{ '' }}
}
```
{% /tab %}
{% /tabs %}
### Server-side tools {% id="server-side-tools" %}
Server-side tools (like Google Search or Code Execution) now yield specific
step types in the `steps` array. While the legacy schema returned these
operations as specific content types within the `outputs` array, the new schema
moves them into the `steps` array. The following examples use Google Search.
#### Before (legacy)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
# Accessing search results in legacy schema
for output in interaction.outputs:
if output.type == "google_search_call":
print(f"Searched for: {output.arguments.queries}")
elif output.type == "google_search_result":
print(f"Found results: {output.result.rendered_content}")
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
// Accessing search results in legacy schema
for (const output of interaction.outputs) {
if (output.type === 'google_search_call') {
console.log(`Searched for: ${output.arguments.queries}`);
} else if (output.type === 'google_search_result') {
console.log(`Found results: ${output.result.renderedContent}`);
}
}
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.8-flash",
"input": "Who won the last Super Bowl?",
"tools": [
{ "type": "google_search" }
]
}'
```
```html
// Response
{
"id": "int_456",
{{ '' }}"outputs": [
{
"type": "google_search_call",
"id": "gs_1",
"arguments": { "queries": ["last Super Bowl winner"] }
},
{
"type": "google_search_result",
"call_id": "gs_1",
"result": {
"rendered_content": "...",
"url": "https://www.nfl.com/super-bowl"
}
},
{
"type": "text",
"text": "The Kansas City Chiefs won the last Super Bowl.",
"annotations": [
{
"start_index": 4,
"end_index": 22,
"source": "https://www.nfl.com/super-bowl"
}
]
}
]{{ '' }},
"status": "completed"
}
```
{% /tab %}
{% /tabs %}
#### After (new schema)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
# Accessing search results in new steps schema
for step in interaction.steps:
if step.type == "google_search_call":
print(f"Searched for: {step.arguments.queries}")
elif step.type == "google_search_result":
print(f"Found results: {step.result[0].search_suggestions}")
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
// Accessing search results in new steps schema
for (const step of interaction.steps) {
if (step.type === 'google_search_call') {
console.log(`Searched for: ${step.arguments.queries}`);
} else if (step.type === 'google_search_result') {
console.log(`Found results: ${step.result[0].search_suggestions}`);
}
}
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
# Opt-in needed before May 26th
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
{{ '**' }}-H "Api-Revision: 2026-05-20" \{{ '**' }}
-d '{
"model": "gemini-3.8-flash",
"input": "Who won the last Super Bowl?",
"tools": [
{ "type": "google_search" }
]
}'
```
```html
// POST Response
{
"id": "int_456",
{{ '' }}"steps": [
{
"type": "google_search_call",
"id": "gs_1",
"arguments": { "queries": ["last Super Bowl winner"] },
"signature": "abc123..."
},
{
"type": "google_search_result",
"call_id": "gs_1",
"result": {
"search_suggestions": "..."
},
"signature": "abc123..."
},
{
"type": "model_output",
"content": [
{
"type": "text",
"text": "The Kansas City Chiefs won the last Super Bowl.",
"annotations": [
{
"type": "url_citation",
"url": "https://www.nfl.com/super-bowl",
"title": "NFL.com",
"start_index": 4,
"end_index": 22
}
]
}
]
}
]{{ '' }},
"status": "completed"
}
```
{% /tab %}
{% /tabs %}
### Streaming {% id="streaming" %}
Streaming exposes new event types:
#### New event types {% id="event-types" %}
- `interaction.created`
- `interaction.completed`
- `step.start`
- `step.delta`
- `step.stop`
`interaction.status_update` is unchanged. It carries the new `status` (for
example `in_progress` or `requires_action`). Every event names its type in
the `event_type` field of the JSON payload, matching the SSE `event:` line.
#### Deprecated event types {% id="deprecated-event-types" %}
The following legacy event types are replaced by the new events listed above:
- `interaction.start` → `interaction.created`
- `content.start` → `step.start`
- `content.delta` → `step.delta`
- `content.stop` → `step.stop`
- `interaction.complete` → `interaction.completed`
**Streaming function calls**: When you use streaming with function calling,
the `step.start` event delivers the function name, and `step.delta` events
stream the arguments as partial JSON strings (using `arguments_delta`). You
must accumulate these deltas to get the full arguments. This differs from
unary calls where you receive the complete function call object at once.
#### Examples {% id="streaming-examples" %}
##### Before (Legacy)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
# Legacy streaming used content.delta
stream = client.interactions.create(
model="gemini-3.8-flash",
input="Explain quantum entanglement in simple terms.",
stream=True,
)
for chunk in stream:
if chunk.event_type == "content.delta":
if chunk.delta.type == "text":
print(chunk.delta.text, end="", flush=True)
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
// Legacy streaming used content.delta
const stream = await client.interactions.create({
model: 'gemini-3.8-flash',
input: 'Explain quantum entanglement in simple terms.',
stream: true,
});
for await (const chunk of stream) {
if (chunk.event_type === 'content.delta') {
if (chunk.delta.type === 'text') {
process.stdout.write(chunk.delta.text);
}
}
}
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.8-flash",
"input": "Explain quantum entanglement in simple terms.",
"stream": true
}'
```
```none
// Response (SSE Lines)
// event: interaction.start
// data: {"id": "int_123", "status": "in_progress"}
//
// event: content.start
// data: {"index": 0, "type": "text"}
//
// event: content.delta
// data: {"delta": {"type": "text", "text": "Quantum entanglement is..."}}
//
// event: content.stop
// data: {"index": 0}
//
// event: interaction.complete
// data: {"id": "int_123", "status": "done", "usage": {"total_tokens": 42}}
```
{% /tab %}
{% /tabs %}
##### After (New Schema)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
# Consuming stream and handling new event types
for event in client.interactions.create(
model="gemini-3.8-flash",
input="Tell me a story.",
stream=True,
):
if event.event_type == "step.delta": # CHANGED: step.delta instead of content.delta
if event.delta.type == "text":
print(event.delta.text, end="")
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
// Consuming stream and handling new event types
const stream = await client.interactions.create({
model: 'gemini-3.8-flash',
input: 'Tell me a story.',
stream: true,
});
for await (const event of stream) {
if (event.event_type === 'step.delta') { // CHANGED: step.delta instead of content.delta
if (event.delta.type === 'text') {
process.stdout.write(event.delta.text);
}
}
}
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
{{ '**' }}# Opt-in needed before May 26th{{ '**' }}
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
{{ '**' }}-H "Api-Revision: 2026-05-20" \{{ '**' }}
-d '{
"model": "gemini-3.8-flash",
"input": "Tell me a story.",
"stream": true
}'
```
```none
// Response (SSE Lines)
// event: interaction.created
// data: {"interaction": {"id": "int_xyz", "status": "in_progress", "object": "interaction", "model": "gemini-3.8-flash"}, "event_type": "interaction.created"}
//
// event: interaction.status_update
// data: {"interaction_id": "int_xyz", "status": "in_progress", "event_type": "interaction.status_update"}
//
// event: step.start
// data: {"index": 0, "step": {"type": "thought", "signature": "abc123..."}, "event_type": "step.start"}
//
// event: step.stop
// data: {"index": 0, "event_type": "step.stop"}
//
// event: step.start
// data: {"index": 1, "step": {"content": [{"text": "Once upon", "type": "text"}], "type": "model_output"}, "event_type": "step.start"}
//
// event: step.delta
// data: {"index": 1, "delta": {"text": " a time...", "type": "text"}, "event_type": "step.delta"}
//
// event: step.stop
// data: {"index": 1, "event_type": "step.stop"}
//
// event: interaction.completed
// data: {"interaction": {"id": "int_xyz", "status": "completed", "usage": {"total_input_tokens": 10, "total_output_tokens": 5, "total_tokens": 15}}, "event_type": "interaction.completed"} // NEW: Dedicated completion event
```
{% /tab %}
{% /tabs %}
### Stateless Conversation History {% id="stateless-history" %}
If you manage conversation history manually on the client side (stateless use
case), you must update how you string along previous turns.
- **Legacy**: Developers often collected the `outputs` array from responses and sent them back in the `input` field on the next turn.
- **New schema**: You should now collect the `steps` array from the response and pass it in the `input` field of the next request, appending your new user turn as a `user_input` step.
## Output format configuration: `response_format` changes {% id="output-format-config" %}
The updated API consolidates all output format controls into a unified,
polymorphic `response_format` field. This centralizes output configuration at
the top level and keeps `generation_config` focused on model behavior (like
temperature, top_p, and thinking).
### Key changes {% id="response-format-changes" %}
- **The API removes `response_mime_type`.** You now specify the MIME type
per format entry inside `response_format`.
- **`response_format` is now a polymorphic object (or array).** Each
entry has a `type` discriminator (`text`, `audio`, `image`) and
type-specific fields. To request multiple output modalities, pass an
array of format entries.
- **`image_config` moves from `generation_config` to `response_format`.**
You now specify image output settings like `aspect_ratio` and `image_size`
in a `response_format` entry with `"type": "image"`.
### Structured output (JSON) {% id="structured-output" %}
The new schema removes the `response_mime_type` field. Instead, specify the
MIME type and JSON schema inside a `response_format` object with
`"type": "text"`.
#### Before (legacy)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
interaction = client.interactions.create(
model="gemini-3.8-flash",
input="Summarize this article.",
response_mime_type="application/json",
response_format={
"type": "object",
"properties": {
"summary": {"type": "string"}
}
},
)
print(interaction.outputs[-1].text)
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
const interaction = await client.interactions.create({
model: 'gemini-3.8-flash',
input: 'Summarize this article.',
response_mime_type: 'application/json',
response_format: {
type: 'object',
properties: {
summary: { type: 'string' }
}
},
});
console.log(interaction.outputs[-1].text);
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.8-flash",
"input": "Summarize this article.",
"response_mime_type": "application/json",
"response_format": {
"type": "object",
"properties": {
"summary": { "type": "string" }
}
}
}'
```
{% /tab %}
{% /tabs %}
#### After (new schema)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
interaction = client.interactions.create(
model="gemini-3.8-flash",
input="Summarize this article.",
# response_mime_type is removed -- specify mime_type inside response_format
response_format={
"type": "text",
"mime_type": "application/json",
"schema": {
"type": "object",
"properties": {
"summary": {"type": "string"}
}
}
},
)
# Print response
print(interaction.output_text)
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
const interaction = await client.interactions.create({
model: 'gemini-3.8-flash',
input: 'Summarize this article.',
// response_mime_type is removed -- specify mime_type inside response_format
response_format: {
type: 'text',
mime_type: 'application/json',
schema: {
type: 'object',
properties: {
summary: { type: 'string' }
}
}
},
});
// Print response
console.log(interaction.output_text);
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
# Opt-in needed before May 26th
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
{{ '**' }}-H "Api-Revision: 2026-05-20" \{{ '**' }}
-d '{
"model": "gemini-3.8-flash",
"input": "Summarize this article.",
"response_format": {
"type": "text",
"mime_type": "application/json",
"schema": {
"type": "object",
"properties": {
"summary": { "type": "string" }
}
}
}
}'
```
{% /tab %}
{% /tabs %}
### Image configuration {% id="image-config" %}
The new schema removes `image_config` from `generation_config`. You now specify
image output settings in a `response_format` entry with `"type": "image"`.
#### Before (legacy)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
interaction = client.interactions.create(
model="gemini-3.8-flash",
input="Generate an image of a sunset over the ocean.",
generation_config={
"image_config": {
"aspect_ratio": "1:1",
"image_size": "1K"
}
},
)
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
const interaction = await client.interactions.create({
model: 'gemini-3.8-flash',
input: 'Generate an image of a sunset over the ocean.',
generation_config: {
image_config: {
aspect_ratio: '1:1',
image_size: '1K'
}
},
});
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.8-flash",
"input": "Generate an image of a sunset over the ocean.",
"generation_config": {
"image_config": {
"aspect_ratio": "1:1",
"image_size": "1K"
}
}
}'
```
{% /tab %}
{% /tabs %}
#### After (new schema)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
interaction = client.interactions.create(
model="gemini-3.8-flash",
input="Generate an image of a sunset over the ocean.",
# image_config is removed from generation_config -- use response_format
response_format={
"type": "image",
"mime_type": "image/jpeg",
"aspect_ratio": "1:1",
"image_size": "1K"
},
)
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
const interaction = await client.interactions.create({
model: 'gemini-3.8-flash',
input: 'Generate an image of a sunset over the ocean.',
// image_config is removed from generation_config -- use response_format
response_format: {
type: 'image',
mime_type: 'image/jpeg',
aspect_ratio: '1:1',
image_size: '1K'
},
});
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
# Opt-in needed before May 26th
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
{{ '**' }}-H "Api-Revision: 2026-05-20" \{{ '**' }}
-d '{
"model": "gemini-3.8-flash",
"input": "Generate an image of a sunset over the ocean.",
"response_format": {
"type": "image",
"mime_type": "image/jpeg",
"aspect_ratio": "1:1",
"image_size": "1K"
}
}'
```
{% /tab %}
{% /tabs %}
### Audio configuration {% id="audio-config" %}
The new schema replaces `response_modalities: ["audio"]` with a `response_format` entry of `"type": "audio"`.
#### Before (legacy)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
interaction = client.interactions.create(
model="gemini-3.1-flash-tts-preview",
input="Say cheerfully: Have a wonderful day!",
response_modalities=["audio"],
generation_config={
"speech_config": [
{"voice": "Kore"}
]
}
)
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
const interaction = await client.interactions.create({
model: 'gemini-3.1-flash-tts-preview',
input: 'Say cheerfully: Have a wonderful day!',
response_modalities: ['audio'],
generation_config: {
speech_config: [
{ voice: 'Kore' }
]
},
});
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.1-flash-tts-preview",
"input": "Say cheerfully: Have a wonderful day!",
"response_modalities": ["audio"],
"generation_config": {
"speech_config": [
{ "voice": "Kore" }
]
}
}'
```
{% /tab %}
{% /tabs %}
#### After (new schema)
{% tabs %}
{% tab filename="sample.py" label="Python" %}
```python
interaction = client.interactions.create(
model="gemini-3.1-flash-tts-preview",
input="Say cheerfully: Have a wonderful day!",
# response_modalities is removed -- use response_format
response_format={
"type": "audio"
},
generation_config={
"speech_config": [
{"voice": "Kore"}
]
}
)
```
{% /tab %}
{% tab filename="sample.js" label="JavaScript" %}
```javascript
const interaction = await client.interactions.create({
model: 'gemini-3.1-flash-tts-preview',
input: 'Say cheerfully: Have a wonderful day!',
// response_modalities is removed -- use response_format
response_format: {
type: 'audio'
},
generation_config: {
speech_config: [
{ voice: 'Kore' }
]
},
});
```
{% /tab %}
{% tab filename="sample.sh" label="REST" %}
```bash
# Opt-in needed before May 26th
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?key=$GEMINI_API_KEY" \
-H "Content-Type: application/json" \
-H "Api-Revision: 2026-05-20" \
-d '{
"model": "gemini-3.1-flash-tts-preview",
"input": "Say cheerfully: Have a wonderful day!",
"response_format": {
"type": "audio"
},
"generation_config": {
"speech_config": [
{ "voice": "Kore" }
]
}
}'
```
To request multiple output modalities (for example, text and audio together),
pass an array of format entries to `response_format` instead of a single
object.
{% /tab %}
{% /tabs %}
## How to migrate to the new schema {% id="how-to-migrate" %}
### SDK users {% id="sdk-users" %}
Upgrade to the latest SDK version (Python ≥2.0.0, JavaScript ≥2.0.0). The
SDK automatically opts you into the new schema — no code changes needed beyond
updating how you read responses (see examples above). Note that only the new
schema is supported in these SDK versions. Older SDK versions
(Python 1.x.x, JavaScript 1.x.x) will continue to work until the legacy
schema is removed on **June 8, 2026**.
### REST API users {% id="raw-api-users" %}
Add the `Api-Revision: 2026-05-20` header to your requests to opt in to
the new schema now. After **May 26**, the new schema becomes the default for all
requests. You can temporarily opt out with `Api-Revision: 2026-05-07`
until **June 8**, when the API permanently removes the legacy schema.
### Timeline {% id="timeline" %}
| Date | Phase | SDK users | REST API users |
| --- | --- | --- | --- |
| **May 7** | Opt-in | New SDK version available (Python ≥2.0.0, JS ≥2.0.0). Upgrade to get the new schema automatically. | Add `Api-Revision: 2026-05-20` header to opt in. Default remains legacy. |
| **May 26** | Default flip | No action needed if already upgraded. Older SDKs (Python 1.x.x, JS 1.x.x) still work but return legacy responses. | New schema is now the default. Send `Api-Revision: 2026-05-07` header to opt out. |
| **June 8** | Sunset | Python 1.x.x and JS 1.x.x SDK versions will break for Interactions API calls. | Legacy schema removed for Interactions API. `Api-Revision` header ignored. |
{% callout type="note" %}
**Note**: New features shipped after May 7 will only
appear in `steps` responses. Users on the legacy `outputs`
schema will not receive new capabilities until they migrate.
{% /callout %}
## Migration Checklist {% id="migration-checklist" %}
### Steps schema (`steps`)
- Update code to read response content from the `steps` array instead of `outputs`. [See examples](/docs/interactions-breaking-changes-may-2026#basic-unary).
- Verify that your code handles both `user_input` and `model_output` step types. [See examples](/docs/interactions-breaking-changes-may-2026#basic-unary).
- (Function Calling) Update code to find `function_call` steps in the `steps` array. [See examples](/docs/interactions-breaking-changes-may-2026#function-calling).
- (Server-Side Tools) Update code to handle tool-specific steps (e.g., `google_search_call`, `google_search_result`). [See examples](/docs/interactions-breaking-changes-may-2026#server-side-tools).
- (Stateless History) Update history management to pass the `steps` array in the `input` field of the next request. [See details](/docs/interactions-breaking-changes-may-2026#stateless-history).
- (Streaming only) Update client to listen for new SSE event types (`interaction.created`, `step.delta`, etc.). [See examples](/docs/interactions-breaking-changes-may-2026#streaming).
### Output format configuration (`response_format`)
- Replace `response_mime_type` with a `mime_type` field inside `response_format`. [See examples](/docs/interactions-breaking-changes-may-2026#structured-output).
- Wrap your existing `response_format` JSON schema inside a `{"type": "text", "schema": ...}` object. [See examples](/docs/interactions-breaking-changes-may-2026#structured-output).
- (Image Generation) Move `image_config` from `generation_config` to a `{"type": "image", ...}` entry in `response_format`. [See examples](/docs/interactions-breaking-changes-may-2026#image-config).
- (Speech Generation) Replace `response_modalities=["audio"]` with a `{"type": "audio"}` entry in `response_format`. [See examples](/docs/interactions-breaking-changes-may-2026#audio-config).
- (Multimodal) Convert `response_format` from a single object to an array when requesting multiple output modalities.