Skip to content

Interactions API

Gunpal Jain edited this page Nov 15, 2026 · 1 revision

Interactions API

The Interactions API (/interactions) is a stateful API for model and agent interactions. Each call creates an Interaction that the server can store, stream, run in the background and continue later. It is also the way to call agents such as Deep Research and Antigravity.

The SDK exposes it through InteractionsClient (namespace GenerativeAI.Clients). It follows python-genai's client.interactions, including stream reconnection and automatic continuation of long outputs.

Platform Support
Gemini API Yes
Vertex AI The client builds the Vertex URL (.../projects/{project}/locations/{location}/interactions). Whether a model is available there depends on the project and region.

Prerequisites

  • NuGet package: Google_GenerativeAI
  • A Gemini API key (GOOGLE_API_KEY / GEMINI_API_KEY) or Vertex AI credentials. See Authentication.
using GenerativeAI;
using GenerativeAI.Clients;
using GenerativeAI.Types;

// Either use a factory method...
var googleAi = new GoogleAi(apiKey);
InteractionsClient client = googleAi.CreateInteractionsClient();

// ...or construct it directly from a platform adapter.
var client2 = new InteractionsClient(new GoogleAIPlatformAdapter(apiKey));

Model IDs for the Interactions API are in InteractionModels (for example InteractionModels.Gemini38Flash). Agent IDs are in InteractionAgents (for example InteractionAgents.DeepResearchPreview042026).

Create an interaction

var interaction = await client.CreateAsync(InteractionModels.Gemini38Flash, "Explain RAG in two sentences.");

Console.WriteLine(interaction.Id);      // keep it to fetch, continue or delete later
Console.WriteLine(interaction.Status);  // e.g. InteractionStatuses.Completed
Console.WriteLine(interaction.OutputText);

For more options, use CreateInteractionRequest:

var request = new CreateInteractionRequest
{
    Model = InteractionModels.Gemini38Flash,
    Input = "Write a haiku about the ocean.",          // string converts to InteractionInput implicitly
    SystemInstruction = "You are a concise poet.",
    GenerationConfig = new InteractionGenerationConfig
    {
        MaxOutputTokens = 512,
        Temperature = 0.7,
        ThinkingLevel = InteractionThinkingLevels.Low
    },
    Tools = new List<InteractionTool> { new InteractionGoogleSearchTool() }
};

var result = await client.CreateAsync(request);
Console.WriteLine(result.OutputText);

Useful properties of Interaction: Id, Status, Steps, Usage (InteractionUsage), OutputText, OutputImage, OutputAudio, OutputVideo, FunctionCalls, ContinuationToken and Errors.

Request rules (checked by the client before sending; an ArgumentException is thrown otherwise):

  • Set exactly one of Model or Agent.
  • GenerationConfig and CachedContent cannot be used with Agent.
  • AgentConfig cannot be used with Model.

Multi-turn conversations

The server stores interactions by default (Store is null/true). To continue a conversation, reference the previous interaction:

var first = await client.CreateAsync(InteractionModels.Gemini38Flash, "My name is Ada.");
var second = await client.CreateAsync(new CreateInteractionRequest
{
    Model = InteractionModels.Gemini38Flash,
    Input = "What is my name?",
    PreviousInteractionId = first.Id
});

Thinking levels

InteractionGenerationConfig.ThinkingLevel takes a value from InteractionThinkingLevels: Minimal, Low, Medium, High, XHigh.

Not every model accepts every level. For example, gemini-3.8-flash (InteractionModels.Gemini38Flash) accepts low, medium and high, but not minimal. The server rejects an unsupported level with a 400 error. Use Low when you want cheap, fast requests.

Streaming

StreamAsync sends stream=true and yields Server-Sent Events as typed InteractionSseEvent objects:

var request = new CreateInteractionRequest
{
    Model = InteractionModels.Gemini38Flash,
    Input = "Tell me a short story.",
    GenerationConfig = new InteractionGenerationConfig { ThinkingLevel = InteractionThinkingLevels.Low }
};

await foreach (var e in client.StreamAsync(request))
{
    switch (e)
    {
        case InteractionCreatedEvent created:
            Console.WriteLine($"Interaction {created.Interaction?.Id} created");
            break;
        case InteractionStepDeltaEvent { Delta: InteractionTextDelta delta }:
            Console.Write(delta.Text);
            break;
        case InteractionStatusUpdateEvent status:
            Console.WriteLine($"\nStatus: {status.Status}");
            break;
        case InteractionCompletedEvent completed:
            Console.WriteLine($"\nDone: {completed.Interaction?.Status}");
            break;
        case InteractionErrorEvent error:
            Console.WriteLine($"Error: {error.Error?.Message}");
            break;
    }
}

Event types: InteractionCreatedEvent, InteractionStepStartEvent, InteractionStepDeltaEvent, InteractionStepStopEvent, InteractionStatusUpdateEvent, InteractionCompletedEvent, InteractionErrorEvent and UnknownInteractionSseEvent. Delta types include InteractionTextDelta, InteractionThoughtSummaryDelta, InteractionArgumentsDelta, InteractionImageDelta, InteractionAudioDelta and others.

Stream reconnection. If the connection drops after the interaction was created, StreamAsync resumes from the last received event ID automatically, up to MaxStreamReconnects times (default 3; set 0 to disable). You can also resume a stream yourself, or stream an existing (for example background) interaction:

await foreach (var e in client.ResumeStreamAsync(interactionId, lastEventId: lastSeenEventId))
{
    // ...
}

Background mode

Set Background = true to queue the interaction and return immediately. Then poll it with WaitForCompletionAsync, which returns once the status is no longer in_progress or queued:

var created = await client.CreateAsync(new CreateInteractionRequest
{
    Model = InteractionModels.Gemini38Flash,
    Input = "Summarize the history of the printing press.",
    Background = true
});

var final = await client.WaitForCompletionAsync(
    created.Id!,
    pollInterval: TimeSpan.FromSeconds(5),   // default 10 s
    timeout: TimeSpan.FromMinutes(10));      // throws TimeoutException when exceeded

if (final.Status == InteractionStatuses.Completed)
    Console.WriteLine(final.OutputText);

Agents normally run in the background:

var research = await client.CreateAsync(new CreateInteractionRequest
{
    Agent = InteractionAgents.DeepResearchPreview042026,
    Input = "Compare recent approaches to battery recycling.",
    Background = true
});
var report = await client.WaitForCompletionAsync(research.Id!, timeout: TimeSpan.FromMinutes(30));

Cancel a running background interaction with CancelAsync(id).

Instead of polling, you can also receive a webhook when an interaction finishes: set CreateInteractionRequest.WebhookConfig (InteractionWebhookConfig with Uris and UserMetadata) or register a webhook for WebhookEvents.InteractionCompleted. See Webhooks.

Get and delete

var fetched = await client.GetAsync(interactionId, includeInput: true);
await client.DeleteAsync(interactionId);

IDs with an interactions/ prefix are accepted.

Automatic continuation

Very long outputs can end with status InteractionStatuses.RequiresContinuation and a ContinuationToken. Like python-genai, CreateAsync continues such interactions for you:

  • EnableAutomaticContinuation (default true): resume while the server asks for it. The returned interaction is the last hop, and its Steps contain the steps of all hops.
  • MaxContinuations (default 10): the maximum number of extra requests per CreateAsync call.
  • Background interactions are not continued by the client; the server continues them.

To control it yourself, turn it off and use ContinueAsync (or build the request with the static InteractionsClient.CreateContinuationRequest):

client.EnableAutomaticContinuation = false;

var interaction = await client.CreateAsync(request);
while (interaction.Status == InteractionStatuses.RequiresContinuation)
{
    interaction = await client.ContinueAsync(interaction, request);
}

Each continuation re-processes and bills input tokens.

Error handling

HTTP errors are thrown as GenerativeAI.Exceptions.ApiException, with ErrorCode, ErrorStatus and ErrorMessage:

try
{
    var interaction = await client.CreateAsync(request);
}
catch (ApiException ex) when (ex.ErrorCode == 400)
{
    // For example an unsupported thinking level, or a model/agent that rejects background=true.
    Console.WriteLine($"{ex.ErrorStatus}: {ex.ErrorMessage}");
}
catch (ApiException ex) when (ex.ErrorCode is 429)
{
    // Quota exhausted: retry later.
}

Also check interaction.Status (Failed, Cancelled, Incomplete, BudgetExceeded, RequiresAction) and interaction.Errors. WaitForCompletionAsync throws TimeoutException when its timeout is exceeded.

Related pages

Clone this wiki locally