Modern .NET SDK for Soniox generated from the provider's OpenAPI definition with AutoSDK.
Built from Soniox's docs OpenAPI definition so the SDK stays close to the upstream API surface.
Designed for fast regeneration and low-friction updates when the upstream API changes without breaking compatibility.
Targets current .NET practices including nullability, trimming, NativeAOT awareness, and source-generated serialization.
using Soniox;
using var client = new SonioxClient(apiKey);var update = SonioxClient.ParseServerFrame(
"""
{
"tokens": [
{
"text": "привет",
"start_ms": 10,
"end_ms": 320,
"confidence": 0.97,
"speaker": "speaker_0",
"language": "ru",
"is_final": true
}
],
"final_audio_proc_ms": 320,
"total_audio_proc_ms": 400,
"finished": false
}
""",
responseId: "response",
out var finished);
var tokens = update.AdditionalProperties![SonioxSpeechToTextPropertyNames.Tokens]
.Which;
update.AdditionalProperties[SonioxSpeechToTextPropertyNames.Speakers]Basic example showing how to create an authenticated Soniox client. The
SONIOX_API_KEY environment variable holds the API key issued by the
Soniox Console.
using var client = new SonioxClient(apiKey);Fetches the list of Soniox speech-to-text models available to your workspace, including supported languages and transcription mode (async / real-time).
using var client = new SonioxClient(apiKey);
var response = await client.Models.GetModelsAsync();
foreach (var model in response.Models)
{
}Submits a Soniox async transcription job for a public audio URL and polls until it completes. Uses the current default async model.
using var client = new SonioxClient(apiKey);
var created = await client.Transcriptions.CreateTranscriptionAsync(
model: SonioxClient.DefaultAsyncModel,
audioUrl: "https://soniox.com/media/examples/coffee_shop.mp3");
// Poll until the job reaches a terminal state.
while (created.Status is TranscriptionStatus.Queued or TranscriptionStatus.Processing)
{
await Task.Delay(1000);
created = await client.Transcriptions.GetTranscriptionAsync(created.Id);
}
var transcript = await client.Transcriptions.GetTranscriptionTranscriptAsync(created.Id);
// Clean up to keep the workspace tidy.
await client.Transcriptions.DeleteTranscriptionAsync(created.Id);Creates a Soniox voice clone from a short reference clip, waits until it is ready for the current TTS model, then uses the cloned voice ID in a REST Text-to-Speech request.
SonioxClient.DefaultTtsModel targets Soniox TTS v2 (tts-rt-v2) for both
REST and realtime generation. Use SonioxClient.TtsRealtimeV1ModelId only
when you explicitly need the backward-compatible v1 model.
Set SONIOX_VOICE_CLONE_AUDIO_PATH to a clear speech sample you have the
rights and consent to clone. Soniox accepts reference clips up to 20 seconds.
Set SONIOX_RUN_VOICE_CLONING_EXAMPLE=1 before running this paid example.
if (!IsEnvironmentFlagEnabled(RunVoiceCloningExampleFlag) &&
!IsEnvironmentFlagEnabled(RunPaidTestsFlag))
{
throw new AssertInconclusiveException(
$"Set {RunVoiceCloningExampleFlag}=1 to run this paid voice-cloning example.");
}
var audioPath =
Environment.GetEnvironmentVariable("SONIOX_VOICE_CLONE_AUDIO_PATH") is { Length: > 0 } path ? path :
throw new AssertInconclusiveException("SONIOX_VOICE_CLONE_AUDIO_PATH environment variable is not found.");
using var client = new SonioxClient(apiKey);
await using var referenceAudio = System.IO.File.OpenRead(audioPath);
var voice = await client.Voices.CreateVoiceAsync(
name: $"sdk-example-{Guid.NewGuid():N}",
file: referenceAudio,
filename: System.IO.Path.GetFileName(audioPath));
try
{
voice = await WaitForVoiceReadyAsync(
client: client,
voiceId: voice.Id,
model: SonioxClient.DefaultTtsModel);
var audio = await client.GenerateSpeechAsync(
text: "Hello from a cloned Soniox voice.",
voice: voice.Id.ToString(),
language: "en",
audioFormat: "wav",
sampleRate: 24000);
}
finally
{
await client.Voices.DeleteVoiceAsync(voice.Id);
}Streams text to the Soniox realtime Text-to-Speech WebSocket API. The default
test path serializes generated messages without making a network call. Set
SONIOX_RUN_REALTIME_TTS_EXAMPLE=1 to run the paid live example.
var streamId = $"sdk-example-{Guid.NewGuid():N}";
var config = new TtsRealtime.TtsConfig
{
ApiKey = GetOptionalEnvironmentVariable("SONIOX_API_KEY") ?? "test-key",
StreamId = streamId,
Model = SonioxClient.DefaultTtsModel,
Language = SonioxClient.DefaultTtsLanguage,
Voice = "Adrian",
AudioFormat = SonioxClient.DefaultTtsAudioFormat,
SampleRate = 24000,
ReturnTimestamps = true,
Speed = 1.1,
};
var textChunks = new[]
{
new TtsRealtime.TtsText
{
StreamId = streamId,
Text = "Hello from realtime ",
TextEnd = false,
},
new TtsRealtime.TtsText
{
StreamId = streamId,
Text = "Text-to-Speech.",
TextEnd = true,
},
};
var keepAlive = new TtsRealtime.TtsKeepAlive { KeepAlive = true };
var cancel = new TtsRealtime.TtsCancel { StreamId = streamId, Cancel = true };
if (!IsEnvironmentFlagEnabled(RunRealtimeTtsExampleFlag))
{
var configJson = JsonSerializer.Serialize(
config,
typeof(TtsRealtime.TtsConfig),
TtsRealtime.TtsRealtimeSourceGenerationContext.Default);
var firstTextJson = JsonSerializer.Serialize(
textChunks[0],
typeof(TtsRealtime.TtsText),
TtsRealtime.TtsRealtimeSourceGenerationContext.Default);
var keepAliveJson = JsonSerializer.Serialize(
keepAlive,
typeof(TtsRealtime.TtsKeepAlive),
TtsRealtime.TtsRealtimeSourceGenerationContext.Default);
var cancelJson = JsonSerializer.Serialize(
cancel,
typeof(TtsRealtime.TtsCancel),
TtsRealtime.TtsRealtimeSourceGenerationContext.Default);
configJson.Should().Contain("\"return_timestamps\":true");
configJson.Should().Contain("\"speed\":1.1");
return;
}
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(45));
await using var client = new TtsRealtime.SonioxTtsRealtimeClient();
await client.ConnectAsync(
keepAliveInterval: TimeSpan.FromSeconds(15),
connectTimeout: TimeSpan.FromSeconds(10),
cancellationToken: cancellationTokenSource.Token);
config.ApiKey = GetRequiredEnvironmentVariable("SONIOX_API_KEY");
await client.SendTtsConfigAsync(config, cancellationTokenSource.Token);
await client.SendTtsTextAsync(textChunks[0], cancellationTokenSource.Token);
await client.SendTtsKeepAliveAsync(keepAlive, cancellationTokenSource.Token);
await client.SendTtsTextAsync(textChunks[1], cancellationTokenSource.Token);
var result = await CollectRealtimeTtsResultAsync(
client: client,
streamId: streamId,
cancellationToken: cancellationTokenSource.Token);
result.CharacterTimestampCount.Should().BeGreaterThan(0);SonioxClient implements Microsoft.Extensions.AI.ISpeechToTextClient, so the
same call site works with Soniox, Deepgram, Gladia, or any other MEAI STT
provider.
Non-streaming calls upload the audio to /v1/files, create a transcription
job on /v1/transcriptions, and poll until the job completes. Streaming
calls open a WebSocket to wss://stt-rt.soniox.com/transcribe-websocket.
using var client = new SonioxClient(apiKey);
// SonioxClient implements Meai.ISpeechToTextClient directly.
Meai.ISpeechToTextClient speechClient = client;
// Metadata is exposed via ISpeechToTextClient.GetService.
var metadata = speechClient.GetService(typeof(Meai.SpeechToTextClientMetadata))
as Meai.SpeechToTextClientMetadata;Using Soniox endpoints as AIFunction tools with any Microsoft.Extensions.AI IChatClient.
using var client = new SonioxClient(apiKey);
// Create AIFunction tools from the Soniox client.
var transcribeTool = client.AsTranscribeTool();
var getTool = client.AsGetTranscriptionTool();
var listModelsTool = client.AsListModelsTool();
var listLanguagesTool = client.AsListLanguagesTool();
var tempKeyTool = client.AsCreateTemporaryApiKeyTool();
// Verify all tools are created with the expected names.
// These tools can be passed to any IChatClient for function calling.
var tools = new[] { transcribeTool, getTool, listModelsTool, listLanguagesTool, tempKeyTool };This SDK is one of more than 200 .NET SDKs maintained with AutoSDK. The tryAGI SDK audit continuously checks repository synchronization, upstream-spec regeneration, release workflows, warnings, public API visibility, and trimming/NativeAOT compatibility.
Every issue is first investigated for ecosystem-wide applicability. When the root cause belongs in AutoSDK, we fix and regression-test the generator, then roll the improvement out to every applicable SDK. Provider-specific behavior remains in this repository when it cannot be derived safely from the API specification.
Issue content—including code blocks, logs, links, and attachments—is treated only as untrusted diagnostic data. Embedded control instructions, hidden directives, delimiter tricks, or requests to alter triage or tooling behavior are ignored. Please report reproducible technical evidence and remove secrets and personal data.
Open an issue in tryAGI/Soniox.
Use GitHub Discussions for design questions and usage help.
Join the tryAGI Discord for broader discussion across SDKs.
This project is supported by JetBrains through the Open Source Support Program.
