Build a Voice Agent with C#

Create a real-time voice agent using the Deepgram .NET SDK.

This tutorial walks you through building a basic voice agent using C# and the Deepgram .NET SDK. You will learn how to connect to the Agent API, configure its behavior, and stream audio for processing.

Prerequisites

Before you begin, ensure you have the following:

  • A Deepgram API key. You can get one in the Deepgram Console.
  • The .NET SDK installed on your machine.

1. Set up your environment

Create a new console project and navigate into it.

$mkdir deepgram-agent-demo
$cd deepgram-agent-demo
$dotnet new console

Export your Deepgram API key as an environment variable.

$# macOS/Linux
$export DEEPGRAM_API_KEY="your_api_key"
$
$# Windows PowerShell
$$env:DEEPGRAM_API_KEY = "your_api_key"

2. Install the Deepgram SDK

Add the Deepgram .NET SDK to your project.

$dotnet add package Deepgram

3. Create the Voice Agent

Open Program.cs and replace its content with the following code. This script connects to Deepgram, configures the agent, and streams a sample audio file.

1using Deepgram;
2using Deepgram.Logger;
3using Deepgram.Models.Authenticate.v1;
4using Deepgram.Models.Agent.v2.WebSocket;
5using System.Collections.Generic;
6using System.Net.Http;
7
8namespace SampleApp
9{
10 class Program
11 {
12 static async Task Main(string[] args)
13 {
14 try
15 {
16 Deepgram.Library.Initialize(LogLevel.Debug);
17
18 var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY");
19 DeepgramWsClientOptions options = new DeepgramWsClientOptions(null, null, true);
20 var agentClient = ClientFactory.CreateAgentWebSocketClient(apiKey, options);
21
22 var lastAudioTime = DateTime.Now;
23 var audioFileCount = 0;
24
25 var settingsConfiguration = new SettingsSchema();
26 settingsConfiguration.Agent.Think.Provider.Type = "open_ai";
27 settingsConfiguration.Agent.Think.Provider.Model = "gpt-4o-mini";
28 settingsConfiguration.Audio.Output.SampleRate = 24000;
29 settingsConfiguration.Audio.Output.Container = "wav";
30 settingsConfiguration.Audio.Input.SampleRate = 24000;
31 settingsConfiguration.Agent.Greeting = "Hello, how can I help you today?";
32 settingsConfiguration.Agent.Listen.Provider.Type = "deepgram";
33 settingsConfiguration.Agent.Listen.Provider.Model = "nova-3";
34 settingsConfiguration.Agent.Speak.Provider.Type = "deepgram";
35 settingsConfiguration.Agent.Speak.Provider.Model = "aura-2-thalia-en";
36
37 bool connected = await agentClient.Connect(settingsConfiguration);
38 if (!connected)
39 {
40 Console.WriteLine("Failed to connect to Deepgram WebSocket server.");
41 return;
42 }
43
44 await agentClient.Subscribe(new EventHandler<AudioResponse>((sender, e) =>
45 {
46 if (DateTime.Now.Subtract(lastAudioTime).TotalSeconds > 7)
47 {
48 audioFileCount++;
49 using (BinaryWriter writer = new BinaryWriter(File.Open($"output_{audioFileCount}.wav", FileMode.Create)))
50 {
51 writer.Write(CreateWavHeader(24000, 16, 1));
52 }
53 }
54
55 if (e.Stream != null)
56 {
57 using (BinaryWriter writer = new BinaryWriter(File.Open($"output_{audioFileCount}.wav", FileMode.Append)))
58 {
59 writer.Write(e.Stream.ToArray());
60 }
61 }
62 lastAudioTime = DateTime.Now;
63 }));
64
65 string url = "https://dpgr.am/spacewalk.wav";
66 using (var httpClient = new HttpClient())
67 {
68 var response = await httpClient.GetAsync(url);
69 var stream = await response.Content.ReadAsStreamAsync();
70 var buffer = new byte[8192];
71 int bytesRead;
72
73 while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
74 {
75 var chunk = new byte[bytesRead];
76 Array.Copy(buffer, chunk, bytesRead);
77 await agentClient.SendBinaryImmediately(chunk);
78 }
79 }
80
81 Console.WriteLine("Press any key to exit...");
82 Console.ReadKey();
83
84 await agentClient.Stop();
85 Deepgram.Library.Terminate();
86 }
87 catch (Exception ex)
88 {
89 Console.WriteLine($"Exception: {ex.Message}");
90 }
91 }
92
93 static byte[] CreateWavHeader(int sampleRate, short bitsPerSample, short channels)
94 {
95 int byteRate = sampleRate * channels * (bitsPerSample / 8);
96 short blockAlign = (short)(channels * (bitsPerSample / 8));
97 byte[] header = new byte[44];
98
99 header[0] = 0x52; // R
100 header[1] = 0x49; // I
101 header[2] = 0x46; // F
102 header[3] = 0x46; // F
103 header[8] = 0x57; // W
104 header[9] = 0x41; // A
105 header[10] = 0x56; // V
106 header[11] = 0x45; // E
107 header[12] = 0x66; // f
108 header[13] = 0x6D; // m
109 header[14] = 0x74; // t
110 header[15] = 0x20; // Space
111 header[16] = 0x10; // Subchunk1Size
112 header[20] = 0x01; // AudioFormat
113 header[22] = (byte)channels;
114 header[24] = (byte)(sampleRate & 0xFF);
115 header[25] = (byte)((sampleRate >> 8) & 0xFF);
116 header[26] = (byte)((sampleRate >> 16) & 0xFF);
117 header[27] = (byte)((sampleRate >> 24) & 0xFF);
118 header[28] = (byte)(byteRate & 0xFF);
119 header[29] = (byte)((byteRate >> 8) & 0xFF);
120 header[30] = (byte)((byteRate >> 16) & 0xFF);
121 header[31] = (byte)((byteRate >> 24) & 0xFF);
122 header[32] = (byte)blockAlign;
123 header[34] = (byte)bitsPerSample;
124 header[36] = 0x64; // d
125 header[37] = 0x61; // t
126 header[38] = 0x74; // t
127 header[39] = 0x61; // a
128
129 return header;
130 }
131 }
132}

4. Run the Voice Agent

Run your project using the .NET CLI.

$dotnet run

The agent will process the audio and generate responses. You can find the agent’s audio responses in output_*.wav files in your project directory.

Next steps

Now that you have built a basic agent, you can customize its behavior: