New AssemblyAI-TTS-1: Text-to-speech for voice agents. Learn more
Insights & Use Cases

Transcribe phone calls in real-time in Go with Twilio and AssemblyAI

Learn how to build a real-time phone call transcription system in Go using Twilio MediaStreams and AssemblyAI's Universal-Streaming Speech-to-Text API.

Abstract green half-sphere illustration

Written by

Marcus Olsson

Published on

11 August 2025

In this tutorial, you'll build a server application in Go that transcribes an incoming Twilio phone call into text in real-time using direct API calls to AssemblyAI's Universal-Streaming API.

You'll use a Twilio MediaStream to stream the voice data to your local server application. You'll pass the voice data to AssemblyAI's Universal-Streaming Speech-to-Text API to transcribe the call into text, and then print it in your terminal in real-time.

This tutorial walks you through the code, step-by-step, but you can also find the complete source code at the end of this page or on the GitHub repo here.

Before you get started

To complete this tutorial, you'll need:

Step 1: Set up ngrok

Twilio will need to access your server through a publicly available URL. In this tutorial, you'll use ngrok to create a publicly available URL for an application running on your local computer.

If you already have a preferred way to expose your application publicly, you may skip this step.

Open an ngrok tunnel for port `8080`. ngrok will only tunnel connections while the following command is running:

You'll see something similar to the output below, where the URL next to Forwarding is the publicly available URL that forwards to your local 8080 port (https://84c5df474.ngrok-free.dev in the example output).

Copy the `Forwarding` URL in your terminal output and save it for the next step.

Step 2: Set up Twilio and open a ngrok tunnel

You'll need to register a phone number with Twilio and configure it to call your server application whenever someone calls that number.

  • Sign up for a Twilio account
  • To get a Twilio number, go to your Twilio console and go to `Phone Number > Manage > Buy a number`. There, you will see a list of numbers you can purchase for a small monthly fee - select one and click `Buy`. Note that we only need Voice capabilities for this tutorial.

Navigate to `Phone Numbers > Manage > Active numbers` and select the phone number you bought above. In the `Voice Configuration`, set a `Webhook` for when a call comes in, pasting the ngrok URL you just copied (from the previous step) under URL and setting the HTTP method to HTTP `POST`:

Then scroll down and click `Save Configuration` to save this change.

You have now configured your Twilio number to send a POST request to the ngrok URL when your number is called, and opened a tunnel that forwards this ngrok URL to port `8080` on your local machine.

We now have a working Go application that can successfully receive and respond to a Twilio phone call - it’s time to add in the WebSocket that receives incoming speech.

Step 3: Create a WebSocket server for Twilio media streams

In this step, you'll set up the Go server application to accept the Twilio MediaStream and connect to AssemblyAI's Universal-Streaming Speech-to-Text API.

Create and navigate into a new project directory:

Initialize your Go module:

Install the required dependencies:

Create a new file called main.go with the following content:

Create a `.env` file in your project directory and add your AssemblyAI API key:

Step 4: Define message structures

AssemblyAI's Universal-Streaming API uses specific message formats. Add these struct definitions to handle the different message types:

Step 5: Implement TwiML response handler

When someone calls the phone number, Twilio makes an HTTP request to an endpoint where you define how to respond. You'll use TwiML to define the instructions that tell Twilio what to do when you receive an incoming call.

Update your twilio function:

The TwiML instructs Twilio to:

  1. Say a greeting message to the caller
  2. Connect to a WebSocket stream at the /media endpoint

Step 6: Create audio buffering system

Since Twilio sends very small audio chunks (around 20ms each) but AssemblyAI's Universal-Streaming API requires chunks between 50-1000ms, we need to buffer the audio. Add this audio buffer implementation:

Step 7: Create transcript display system

To handle clean display of partial and final transcripts, add this display manager:

Step 8: Connect to AssemblyAI Universal-Streaming

Now implement the WebSocket connection to AssemblyAI's Universal-Streaming Speech-to-Text API:

This function:

  • Builds the WebSocket URL with the required parameters for Universal-Streaming (v3)
  • Sets the sample rate to 8000 Hz (Twilio's format)
  • Specifies PCM μ-law encoding (Twilio's audio format)
  • Enables formatted turns for better transcript output
  • Configures turn detection parameters for natural conversation flow

Step 9: Handle audio forwarding

Add the function to forward audio from Twilio to AssemblyAI:

Step 10: Handle AssemblyAI responses

Implement the function to process responses from AssemblyAI:

This function handles three types of messages from AssemblyAI:

  • Begin: Session establishment confirmation
  • Turn: Transcript data (partial and final)
  • Termination: Session end notification

The transcript handling logic ensures a smooth user experience by displaying partial transcripts in real-time and replacing them with final formatted versions.

Step 11: Implement the media WebSocket handler

Now implement the complete media function that ties everything together:

Step 12: Add session management

For robustness, add a session manager to track the AssemblyAI connection state (optional):

Step 13: Test your application

Now you're ready to test the complete application:

Start the server:

You should see output like:

Call your Twilio phone number. If prompted by your operating system, allow the application to access the network.

Once instructed by the voice, start speaking to see your call transcribed in your server log:

Most of this logging can be useful for debugging purposes, but can be safely removed to show only the real-time transcript output.

Learn more

In this tutorial, you built a Go application that transcribes incoming phone calls in real-time using Twilio and AssemblyAI's Universal-Streaming Speech-to-Text API.

This implementation demonstrates how to:

  • Handle WebSocket connections for real-time audio streaming
  • Integrate with Twilio's MediaStream for phone call capture
  • Process audio data in mu-law format from Twilio
  • Connect directly to AssemblyAI's WebSocket API for streaming transcription

To keep up with more content like this, make sure you subscribe to our newsletter.

Complete source code

Also available via the GitHub repo here.

Get a free API key

Access AssemblyAI's API with $50 in free credits

Get Free API Key