How to Record Calls and Transcribe
In this guide we will show you how to record any inbound or outbound call and produce a transcription of these recordings. Please ensure you have followed our earlier guide on how to make an outbound call with Bandwidth.
Calls may be recorded or transcribed to enhance customer experience and training, for dispute resolution or for regulatory compliance reasons.
There are two ways you can record a call; with <Record>
or with <StartRecording>
. Please select the use case that best suits your needs.
Use <Record>
if:
- You're capturing a voicemail
- You only need a single party recording
- You're capturing input that should pause the call until finished
Use <StartRecording>
if:
- You want to record both ends (together or separate) of a phone call
- You want to record a call for quality assurance
- You need other BXML verbs to execute while a recording is going on
Recording a Call
Record
The <Record>
verb starts recording in a call and pauses all BXML execution until the recording is terminated by a timeout (maxDuration
) or a terminating digit (terminatingDigits
/). Once the recording ends, BXML execution will continue at the next verb, or at the BXML at the recordCompleteUrl
if this attribute is set.
If the recordingAvailableUrl
attribute is set, this URL will receive a callback once the recording is available to use.
- XML
- Java
- C#
- Ruby
- NodeJS
- Python
- PHP
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<SpeakSentence>Please say your name.</SpeakSentence>
<Record recordCompleteUrl="/nextBxml" maxDuration="10"/>
<!-- Any verbs after this point would be replaced by those returned by the recordCompleteUrl -->
</Response>
The /nextBXML endpoint responds with the following.
<Response>
<SpeakSentence>Thank you.</SpeakSentence>
</Response>
@POST /record_name endpoint
public String recordName() {
SpeakSentence speakSentence = new SpeakSentence("Please say your name.")
Record record = new Record().builder()
.recordCompleteUrl("/nextBXML")
.maxDuration(10)
.build();
Response response = Response()
.withVerbs(speakSentence, record);
return response.ToBxml();
}
@POST /nextBXML endpoint
public String thankYou() {
SpeakSentence speakSentence = new SpeakSentence("Thank you.")
Response response = new Response()
.with(speakSentence);
return response.ToBxml();
}
@POST [/record_name]
public ActionResult recordName() {
SpeakSentence speakSentence = new SpeakSentence
{
Sentence = "Please say your name."
};
Record record = new Record
{
RecordCompleteUrl = "/nextBXML",
MaxDuration = 10
};
Response response = new Response();
response.Add(speakSentence);
response.Add(record);
return new OkObjectResult(response.ToBXML());
}
@POST [/nextBXML]
public ActionResult thankYou() {
SpeakSentence speakSentence = new SpeakSentence
{
Sentence = "Thank you."
};
Response response = new Response();
response.Add(speakSentence);
return new OkObjectResult(response.ToBXML());
}
post '/record_name' do
speak_sentence = Bandwidth::Bxml::SpeakSentence.new('Please say your name.')
record = Bandwidth::Bxml::Record.new({
record_complete_url: '/nextBXML',
max_duration: 10
})
response = Bandwidth::Bxml::Response.new([speak_sentence, record])
return response.to_bxml
end
post '/nextBXML' do
speak_sentence = Bandwidth::Bxml::SpeakSentence.new('Thank you.')
response = Bandwidth::Bxml::Response.new([speak_sentence])
return response.to_bxml
end
@POST ['/record_name'] (req, res) => {
const speakSentence = new Bxml.SpeakSentence('Please say your name.');
const record = new Bxml.Record({
recordCompleteUrl: "/nextBXML",
maxDuration: 10
});
const response = new Bxml.Response([speakSentence, record]);
console.log(response.toBxml());
res.status(200).send(response.toBxml());
}
@POST ['/nextBXML'] (req, res) => {
const speakSentence = new Bxml.SpeakSentence('Thank you.');
const response = new Bxml.Response(speakSentence);
console.log(response.toBxml());
res.status(200).send(response.toBxml());
}
@POST '/record_name'
def recordName():
speak_sentence = SpeakSentence(
text="Please say your name.",
)
record = Record(
record_complete_url="/nextBXML",
max_duration=10
)
response = Response()
response.add_verb(speak_sentence)
response.add_verb(record)
return response.to_bxml()
@POST '/nextBXML'
def thankYou():
speak_sentence = SpeakSentence(
text="Thank you.",
)
response = Response()
response.add_verb(speak_sentence)
return response.to_bxml()
@POST('/record_name)
function recordName(Request $request, Response $response) {
$speakSentence = new BandwidthLib\Voice\Bxml\SpeakSentence("Please say your name.");
$record = new BandwidthLib\Voice\Bxml\Record();
$record->recordCompleteUrl("/nextBXML");
$record->maxDuration(10);
$response = new BandwidthLib\Voice\Bxml\Response();
$response->addVerb($speakSentence);
$response->addVerb($record);
$bxml = $response->toBxml();
$response = $response->withStatus(200)->withHeader('Content-Type', 'application/xml');
$response->getBody()->write($bxml);
return $response;
}
@POST('/nextBXML')
function thankYou(Request $request, Response $response) {
$speakSentence = new BandwidthLib\Voice\Bxml\SpeakSentence("Thank you.");
$response = new BandwidthLib\Voice\Bxml\Response();
$response->addVerb($speakSentence);
$bxml = $response->toBxml();
$response = $response->withStatus(200)->withHeader('Content-Type', 'application/xml');
$response->getBody()->write($bxml);
return $response;
}
In this example, a <SpeakSentence>
prompts the caller to say their name. The record then records the next 10 seconds, after which it will then play the BXML located at the /recordCompleteUrl
endpoint, which says thank you.
StartRecording
The <StartRecording>
verb starts recording in a call without pausing BXML execution. The <PauseRecording>
, <ResumeRecording>
, and <StopRecording>
BXML verbs can be used to toggle the recording. Recording is terminated by either the call ending, or by a StopRecording verb.
Much like the Record verb, <StartRecording>
also has a recordingAvailableUrl
attribute to receive the recording available callback.
- XML
- Java
- C#
- Ruby
- NodeJS
- Python
- PHP
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<StartRecording recordingAvailableUrl="https://myapp.test/noBXML"/> //Note: This will send a callback that only notifies you that your recording is ready.
<SpeakSentence>Hello secret agent. What is your message?</SpeakSentence>
<Pause duration="10"/>
<PauseRecording/>
<SpeakSentence>Please say your secret passcode to send. Don't worry, the recording is paused!</SpeakSentence>
<Pause duration="5"/>
<SpeakSentence>Restarting the recording now.</SpeakSentence>
<ResumeRecording/>
<SpeakSentence>Thank you agent. Good luck on your mission!</SpeakSentence>
<StopRecording/>
<SpeakSentence>Recording has been stopped.</SpeakSentence>
</Response>
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST /secret_agent_endpoint endpoint
public String record_call() {
StartRecording startRecording = new StartRecording().builder()
.recordingAvailableUrl("https://myapp.test/noBXML")
.build();
SpeakSentence intro_tts = new SpeakSentence("Hello secret agent. What is your message?");
Pause pause1 = Pause(10.0);
PauseRecording pauseRecording = PauseRecording();
SpeakSentence passcode_tts = SpeakSentence("Please say your secret passcode to send. Don't worry, the recording is paused!");
Pause pause2 = Pause(5.0)
ResumeRecording resumeRecording = new ResumeRecording();
SpeakSentence goodbye_tts = new SpeakSentence("Thank you agent. Good luck on your mission!");
StopRecording stopRecording = new StopRecording();
Response response = new Response();
String bxml = response.withVerbs(startRecording, intro_tts, pause1, pauseRecording, passcode_tts, pause2,
resumeRecording, goodbye_tts, stopRecording).toBXML();
return bxml;
}
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST [/secret_agent_endpoint]
public ActionResult record_call() {
StartRecording startRecording = new StartRecording
{
RecordingAvailableUrl = "https://myapp.test/noBXML"
};
SpeakSentence intro_tts = new SpeakSentence
{
Sentence = "Hello secret agent. What is your message?",
};
Pause pause1 = new Pause{Duration = 10};
PauseRecording pauseRecording = new PauseRecording();
SpeakSentence passcode_tts = new SpeakSentence
{
Sentence = "Please say your secret passcode to send. Don't worry, the recording is paused!",
};
Pause pause2 = new Pause{Duration = 5};
ResumeRecording resumeRecording = new ResumeRecording();
SpeakSentence goodbye_tts = new SpeakSentence
{
Sentence = "Thank you agent. Good luck on your mission!",
};
StopRecording stopRecording = new StopRecording();
Response response = new Response(startRecording, intro_tts, pause1, pauseRecording,
passcode_tts, pause2, resumeRecording, goodbye_tts, stopRecording);
return new OkObjectResult(response.ToBXML());
}
**Note: The endpoint headers are pseudocoded. Your implementation will look different
post '/secret_agent_endpoint' do
start_recording = Bandwidth::Bxml::StartRecording.new({ recording_available_url: 'https://myapp.test/noBXML' })
speak_sentence_intro = Bandwidth::Bxml::SpeakSentence.new('Hello secret agent. What is your message?')
pause_1 = Bandwidth::Bxml::Pause.new({ duration: 10 })
pause_recording = Bandwidth::Bxml::PauseRecording.new
speak_sentence_passcode = Bandwidth::Bxml::SpeakSentence.new("Please say your secret passcode to send. Don't worry, the recording is paused!")
pause_2 = Bandwidth::Bxml::Pause.new({ duration: 5 })
resume_recording = Bandwidth::Bxml::ResumeRecording.new()
speak_sentence_goodbye = Bandwidth::Bxml::SpeakSentence.new('Thank you agent. Good luck on your mission!')
stop_recording = Bandwidth::Bxml::StopRecording.new()
response = Bandwidth::Bxml::Response.new([
start_recording,
speak_sentence_intro,
pause_1,
pause_recording,
speak_sentence_passcode,
pause_2,
resume_recording,
speak_sentence_goodbye,
stop_recording
])
return response.to_bxml
end
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST ['/secret_agent_endpoint'] (req, res) => {
const startRecording = new Bxml.StartRecording({ recordingAvailableUrl: "https://myapp.test/noBXML" });
const intro_tts = new Bxml.SpeakSentence('Hello secret agent. What is your message?');
const pause1 = new Bxml.Pause({ duration: 10 });
const pauseRecording = new Bxml.PauseRecording();
const passcode_tts = new Bxml.SpeakSentence("Please say your secret passcode to send. Don't worry, the recording is paused!");
const pause2 = new Bxml.Pause({ duration: 5 });
const resumeRecording = new Bxml.ResumeRecording();
const goodbye_tts = new Bxml.SpeakSentence('Thank you agent. Good luck on your mission!');
const stopRecording = new Bxml.StopRecording();
const response = new Bxml.Response([startRecording, intro_tts, pause1, pauseRecording,
passcode_tts, pause2, resumeRecording, goodbye_tts, stopRecording]);
res.status(200).send(response.toBxml());
}
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST '/secret_agent_endpoint'
def record_call():
start_recording = StartRecording(recording_available_url="https://myapp.test/noBXML")
intro_tts = SpeakSentence(
text="Hello secret agent. What is your message?",
)
pause1 = Pause(duration=10)
pause_recording = PauseRecording()
passcode_tts = SpeakSentence(
text="Please say your secret passcode to send. Don't worry, the recording is paused!",
)
pause2 = Pause(duration=5)
resumeRecording = ResumeRecording()
goodbye_tts = SpeakSentence(
text="Thank you agent. Good luck on your mission!",
)
stop_recording = StopRecording()
response = Response()
response.add_verb(start_recording)
response.add_verb(intro_tts)
response.add_verb(pause1)
response.add_verb(pause_recording)
response.add_verb(passcode_tts)
response.add_verb(pause2)
response.add_verb(resumeRecording)
response.add_verb(goodbye_tts)
response.add_verb(stop_recording)
return response.to_bxml()
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST('/secret_agent_endpoint)
function record_call(Request $request, Response $response) {
$startRecording = new BandwidthLib\Voice\Bxml\StartRecording();
$startRecording->recordingAvailableUrl("https://myapp.test/noBXML");
$intro_tts = new BandwidthLib\Voice\Bxml\SpeakSentence("Hello secret agent. What is your message?");
$pause1 = new BandwidthLib\Voice\Bxml\Pause();
$pause1->duration(10);
$pauseRecording = new BandwidthLib\Voice\Bxml\PauseRecording();
$passcode_tts = new BandwidthLib\Voice\Bxml\SpeakSentence("Please say your secret passcode to send. Don't worry, the recording is paused!");
$pause2 = new BandwidthLib\Voice\Bxml\Pause();
$pause2->duration(5);
$resumeRecording = new BandwidthLib\Voice\Bxml\ResumeRecording();
$goodbye_tts = new BandwidthLib\Voice\Bxml\SpeakSentence("Thank you agent. Good luck on your mission!");
$stopRecording = new BandwidthLib\Voice\Bxml\StopRecording();
$response->addVerb($startRecording);
$response->addVerb($intro_tts);
$response->addVerb($pause1);
$response->addVerb($pauseRecording);
$response->addVerb($passcode_tts);
$response->addVerb($pause2);
$response->addVerb($resumeRecording);
$response->addVerb($goodbye_tts);
$response->addVerb($stopRecording);
$bxml = $response->toBxml();
$response = $response->withStatus(200)->withHeader('Content-Type', 'application/xml');
$response->getBody()->write($bxml);
return $response;
}
The example above uses all the different forms of the controllable recording bxml, with StartRecording
, PauseRecording
, ResumeRecording
, and StopRecording
. In this scenario, the recording is started, a message is given, then the recording is paused to allow for sensitive information to be left out of the recording. Once the information is said, the recording is resumed to catch the last part of the conversation, then stopped to hang up the call.
Download Recording
After the call has completed you can retrieve information on the recording and download the file in .mp3 or .wav format. Recordings are stored for 30 days.
- cURL
- Java
- C#
- Ruby
- NodeJS
- Python
- PHP
curl 'https://voice.bandwidth.com/api/v2/accounts/$BW_ACCOUNT_ID/calls/{CALL_ID}/recordings/{RECORDING_ID}' \
-u {BANDWIDTH_USERNAME}:{BANDWIDTH:PASSWORD}
import com.bandwidth.sdk.ApiClient;
import com.bandwidth.sdk.ApiException;
import com.bandwidth.sdk.Configuration;
import com.bandwidth.sdk.auth.*;
import com.bandwidth.sdk.models.*;
import com.bandwidth.sdk.api.RecordingsApi;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("http://localhost");
// Configure HTTP basic authorization: Basic
HttpBasicAuth Basic = (HttpBasicAuth) defaultClient.getAuthentication("Basic");
Basic.setUsername("YOUR USERNAME");
Basic.setPassword("YOUR PASSWORD");
RecordingsApi apiInstance = new RecordingsApi(defaultClient);
String accountId = "9900000"; // String | Your Bandwidth Account ID.
String callId = "c-15ac29a2-1331029c-2cb0-4a07-b215-b22865662d85"; // String | Programmable Voice API Call ID.
String recordingId = "r-15ac29a2-1331029c-2cb0-4a07-b215-b22865662d85"; // String | Programmable Voice API Recording ID.
try {
File result = apiInstance.downloadCallRecording(accountId, callId, recordingId);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling RecordingsApi#downloadCallRecording");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
using System;
using System.Threading.Tasks;
using Bandwidth.Standard;
using Bandwidth.Standard.Exceptions;
using Bandwidth.Standard.Voice.Models;
class Program
{
static async Task Main(string[] args)
{
var client = new BandwidthClient.Builder()
.VoiceBasicAuthCredentials({BW_USERNAME}, {BW_PASSWORD})
.Build();
try
{
var response = await client.Voice.APIController.GetCallRecordingAsync({ACCOUNT_ID}, {CALL_ID}, {RECORDING_ID});
Console.WriteLine(response.Data);
}
catch (ApiException e)
{
Console.WriteLine(e.Message);
}
}
}
require 'bandwidth-sdk'
begin
BW_USERNAME = ENV.fetch('BW_USERNAME')
BW_PASSWORD = ENV.fetch('BW_PASSWORD')
BW_ACCOUNT_ID = ENV.fetch('BW_ACCOUNT_ID')
CALL_ID = ENV.fetch('CALL_ID')
RECORDING_ID = ENV.fetch('RECORDING_ID')
rescue
p 'Please set the environmental variables defined in the README'
exit(-1)
end
Bandwidth.configure do |config|
config.username = BW_USERNAME
config.password = BW_PASSWORD
end
recordings_api_instance = Bandwidth::RecordingsApi.new
begin
response = calls_api_instance.get_call_recording(BW_ACCOUNT_ID, CALL_ID, RECORDING_ID)
p response.application_id
rescue Bandwidth::ApiError => e
p e.code
end
import { RecordingsApi, Configuration } from 'bandwidth-sdk';
const BW_USERNAME = process.env.BW_USERNAME;
const BW_PASSWORD = process.env.BW_PASSWORD;
const BW_ACCOUNT_ID = process.env.BW_ACCOUNT_ID;
const config = new Configuration({
BW_USERNAME,
BW_PASSWORD
});
const recordingsApi = new RecordingsApi(config);
const callId = 'c-abc12345-6defabc1-2345-6def-abc1-23456defabc1';
const recordingId = 'r-abc12345-6def-abc1-2345-6defabc12345';
const { status, data } = await recordingsApi.getCallRecording(
BW_ACCOUNT_ID,
callId,
recordingId
);
import os
import bandwidth
from pprint import pprint
configuration = bandwidth.Configuration(
username=os.environ["BW_USERNAME"],
password=os.environ["BW_PASSWORD"]
)
with bandwidth.ApiClient(configuration) as api_client:
api_instance = bandwidth.RecordingsApi(api_client)
account_id = os.environ["BW_ACCOUNT_ID"]
call_id = {CALL_ID}
recording_id = {RECORDING_ID}
try:
api_response = api_instance.get_call_recording(account_id, call_id, recording_id)
print("The response of RecordingsApi->get_call_recording:\n")
pprint(api_response)
except Exception as e:
print("Exception when calling RecordingsApi->get_call_recording: %s\n" % e)
require "vendor/autoload.php";
$config = new BandwidthLib\Configuration(
array(
'voiceBasicAuthUserName' => {BW_USERNAME},
'voiceBasicAuthPassword' => {BW_PASSWORD},
)
);
$client = new BandwidthLib\BandwidthClient($config);
$voiceClient = $client->getVoice()->getClient();
try {
$response = $voiceClient->getCallRecording({ACCOUNT_ID}, {CALL_ID}, {RECORDING_ID});
print_r($response->getResult()->applicationId);
} catch (BandwidthLib\APIException $e) {
print_r($e->getResponseCode());
}
Transcribing a Call
Request Transcription of an Existing Recording
You can also choose to request transcription of a recording after it has been completed via the API.
Transcription can succeed only for recordings of length greater than 500 milliseconds and less than 4 hours.
- Payload
- cURL
- Java
- C#
- Ruby
- NodeJS
- Python
- PHP
//Remember to add an auth header with your Bandwidth credentials
POST https://voice.bandwidth.com/api/v2/accounts/{accountId}/calls/{callId}/recordings/{recordingId}/transcription
{
"callbackUrl": "http://transcription.test",
}
//Remember to add an auth header with your Bandwidth credentials
curl 'https://voice.bandwidth.com/api/v2/accounts/{accountId}/calls/{callId}/recordings/{recordingId}/transcription' \
-X POST \
-u {BANDWIDTH_USERNAME}:{BANDWIDTH:PASSWORD}
-H 'Content-Type: application/json' \
-d '{
"callbackUrl": "http://example.test/transcription",
}'
import com.bandwidth.sdk.ApiClient;
import com.bandwidth.sdk.ApiException;
import com.bandwidth.sdk.Configuration;
import com.bandwidth.sdk.auth.*;
import com.bandwidth.sdk.models.*;
import com.bandwidth.sdk.api.RecordingsApi;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("http://localhost");
// Configure HTTP basic authorization: Basic
HttpBasicAuth Basic = (HttpBasicAuth) defaultClient.getAuthentication("Basic");
Basic.setUsername("YOUR USERNAME");
Basic.setPassword("YOUR PASSWORD");
RecordingsApi apiInstance = new RecordingsApi(defaultClient);
String accountId = "9900000"; // String | Your Bandwidth Account ID.
String callId = "c-15ac29a2-1331029c-2cb0-4a07-b215-b22865662d85"; // String | Programmable Voice API Call ID.
String recordingId = "r-15ac29a2-1331029c-2cb0-4a07-b215-b22865662d85"; // String | Programmable Voice API Recording ID.
try {
TranscriptionList result = apiInstance.getCallTranscription(accountId, callId, recordingId);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling RecordingsApi#getCallTranscription");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
using System;
using System.Threading.Tasks;
using Bandwidth.Standard;
using Bandwidth.Standard.Exceptions;
using Bandwidth.Standard.Voice.Models;
static async Task Main(string[] args) {
//Remember to fill in all variables!
var client = new BandwidthClient.Builder()
.VoiceBasicAuthCredentials({BW_USERNAME}, {BW_PASSWORD})
.Build();
var request = new TranscribeRecordingRequest
{
CallbackUrl = "http://example.test/transcription"
};
//remember to add auth for your application if needed!
try {
var response = await client.Voice.APIController.CreateTranscribeCallRecordingAsync({ACCOUNT_ID}, {CALL_ID}, {RECORDING_ID}, request);
Console.WriteLine(response.Data);
} catch (ApiException e) {
Console.WriteLine(e.Message);
}
}
require 'bandwidth-sdk'
begin
BW_USERNAME = ENV.fetch('BW_USERNAME')
BW_PASSWORD = ENV.fetch('BW_PASSWORD')
BW_ACCOUNT_ID = ENV.fetch('BW_ACCOUNT_ID')
CALL_ID = ENV.fetch('CALL_ID')
RECORDING_ID = ENV.fetch('RECORDING_ID')
rescue
p 'Please set the environmental variables defined in the README'
exit(-1)
end
Bandwidth.configure do |config|
config.username = BW_USERNAME
config.password = BW_PASSWORD
end
recordings_api_instance = Bandwidth::RecordingsApi.new
body = Bandwidth::TranscribeRecording.new(callback_url: 'http://example.test/transcription')
begin
recordings_api_instance.transcribe_call_recording(BW_ACCOUNT_ID, CALL_ID, RECORDING_ID, body)
rescue Bandwidth::ApiError => e
p e.code
end
import { RecordingsApi, Configuration } from 'bandwidth-sdk';
const BW_USERNAME = process.env.BW_USERNAME;
const BW_PASSWORD = process.env.BW_PASSWORD;
const BW_ACCOUNT_ID = process.env.BW_ACCOUNT_ID;
const config = new Configuration({
BW_USERNAME,
BW_PASSWORD
});
const recordingsApi = new RecordingsApi(config);
const callId = 'c-abc12345-6defabc1-2345-6def-abc1-23456defabc1';
const recordingId = 'r-abc12345-6def-abc1-2345-6defabc12345';
const transcribeRecording = {
callbackUrl: `${BASE_CALLBACK_URL}/transcriptions`,
tag: callId
};
const { status } = await recordingsApi.transcribeCallRecording(
BW_ACCOUNT_ID,
callId,
recordingId,
transcribeRecording
);
import os
import bandwidth
configuration = bandwidth.Configuration(
username=os.environ["BW_USERNAME"],
password=os.environ["BW_PASSWORD"]
)
with bandwidth.ApiClient(configuration) as api_client:
api_instance = bandwidth.RecordingsApi(api_client)
account_id = os.environ["BW_ACCOUNT_ID"]
call_id = { CALL_ID }
recording_id = { RECORDING_ID }
transcribe_recording = bandwidth.TranscribeRecording(
callback_url='https://test.com'
)
try:
# Create Transcription Request
api_instance.transcribe_call_recording(account_id, call_id, recording_id, transcribe_recording)
except Exception as e:
print("Exception when calling RecordingsApi->transcribe_call_recording: %s\n" % e)
<?php
require "vendor/autoload.php";
$config = new BandwidthLib\Configuration(
array(
'voiceBasicAuthUserName' => {BW_USERNAME},
'voiceBasicAuthPassword' => {BW_PASSWORD},
)
);
$client = new BandwidthLib\BandwidthClient($config);
$voiceClient = $client->getVoice()->getClient();
$body = new BandwidthLib\Voice\Models\TranscribeRecordingRequest();
$body->callbackUrl = "http://example.test/transcription";
#remember to add auth for your application if needed!
try {
$voiceClient->createTranscribeCallRecording({ACCOUNT_ID}, {CALL_ID}, {RECORDING_ID}, $body);
} catch (BandwidthLib\APIException $e) {
print_r($e->getResponseCode());
}
In this example, using our callId
and recordingId
we are requesting to download a specific recording. You can use this to download as many recordings as you require.
Request Transcription when creating a Recording
The transcribe attribute can be added to the <Record>
or <StartRecording>
BXML verbs to automatically generate a transcription when the recording is done. If you want to receive a TranscriptionAvailable callback, you can additionally set the transcriptionAvailableUrl to a URL on your callback server and transcriptionAvailableMethod to its associated HTTP method (GET or POST, the default/).
- XML
- Java
- C#
- Ruby
- NodeJS
- Python
- PHP
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Record transcribe='true' transcriptionAvailableUrl="/transcription_callback" maxDuration="10"/>
</Response>
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST /incoming_calls endpoint
public String transcribe_call() {
Record record = new Record().builder()
.transcribe(true)
.transcriptionAvailableUrl("/transcription_callback")
.maxDuration(10)
.build();
Response response = new Response();
String bxml = response.with(record).toBXML();
return bxml;
}
@POST /transcription_callback endpoint
public String alert() {
System.out.println("Oh! A transcription!");
}
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST [/incoming_calls]
public ActionResult transcribe_call() {
Record record = new Record
{
transcribe=true
transcriptionAvailableUrl = "/transcription_callback",
MaxDuration = 10
};
Response response = new Response();
response.Add(record);
return new OkObjectResult(response.ToBXML());
}
@POST [/transcription_callback]
public ActionResult alert() {
Console.WriteLine("Oh! A transcription!");
}
**Note: The endpoint headers are pseudocoded. Your implementation will look different
post '/incoming_calls' do
record = Bandwidth::Bxml::Record.new({
transcribe: true,
transcription_available_url: '/transcription_callback',
max_duration: 10
})
response = Bandwidth::Bxml::Response.new([record])
return response.to_bxml
end
post '/transcription_callback' do
# handle transcription callback
end
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST ['/incoming_calls'] (req, res) => {
const record = new Bxml.Record({
transcribe: true,
transcriptionAvailableUrl: "/transcription_callback",
maxDuration: 10
});
const response = new Bxml.Response(record);
console.log(response.toBxml());
res.status(200).send(response.toBxml());
}
@POST ['/transcription_callback'] (req, res) => {
console.log("Oh! A transcription!");
}
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST '/incoming_calls'
def transcribe_call():
record = Record(
transcribe=True,
transcription_available_url="/transcription_callback",
max_duration=10
)
response = Response()
response.add_verb(record)
return response.to_bxml()
@POST 'transcription_callback':
def alert():
printf("Oh! A transcription!")
**Note: The endpoint headers are pseudocoded. Your implementation will look different
@POST('/incoming_calls)
function transcribe_call(Request $request, Response $response) {
$record = new BandwidthLib\Voice\Bxml\Record();
$record->transcribe(true);
$record->transcriptionAvailableUrl("/transcription_callback");
$record->maxDuration(10);
$response = new BandwidthLib\Voice\Bxml\Response();
$response->addVerb($record);
$bxml = $response->toBxml();
$response = $response->withStatus(200)->withHeader('Content-Type', 'application/xml');
$response->getBody()->write($bxml);
return $response;
}
@POST('/transcription_callback)
function transcribe_call(Request $request, Response $response) {
echo "Oh! A transcription!"
}
In this example, we have just built on our original <Record>
example to add transcription to our recording and specified a callback URL.
Download Transcription
After the call has completed, you can download the transcribed file in JSON format. Transcriptions are stored for 30 days.
- cURL
- Java
- C#
- Ruby
- NodeJS
- Python
- PHP
curl 'https://voice.bandwidth.com/api/v2/accounts/{accountId}/calls/{callId}/recordings/{recordingId}/transcription' \
-u {BANDWIDTH_USERNAME}:{BANDWIDTH:PASSWORD}
import com.bandwidth.sdk.ApiClient;
import com.bandwidth.sdk.ApiException;
import com.bandwidth.sdk.Configuration;
import com.bandwidth.sdk.auth.*;
import com.bandwidth.sdk.models.*;
import com.bandwidth.sdk.api.RecordingsApi;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath("http://localhost");
// Configure HTTP basic authorization: Basic
HttpBasicAuth Basic = (HttpBasicAuth) defaultClient.getAuthentication("Basic");
Basic.setUsername("YOUR USERNAME");
Basic.setPassword("YOUR PASSWORD");
RecordingsApi apiInstance = new RecordingsApi(defaultClient);
String accountId = "9900000"; // String | Your Bandwidth Account ID.
String callId = "c-15ac29a2-1331029c-2cb0-4a07-b215-b22865662d85"; // String | Programmable Voice API Call ID.
String recordingId = "r-15ac29a2-1331029c-2cb0-4a07-b215-b22865662d85"; // String | Programmable Voice API Recording ID.
try {
TranscriptionList result = apiInstance.getCallTranscription(accountId, callId, recordingId);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling RecordingsApi#getCallTranscription");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
using System;
using System.Threading.Tasks;
using Bandwidth.Standard;
using Bandwidth.Standard.Exceptions;
using Bandwidth.Standard.Voice.Models;
static async Task Main(string[] args)
//Remember to fill in all variables!
var client = new BandwidthClient.Builder()
.VoiceBasicAuthCredentials({BW_USERNAME}, {BW_PASSWORD})
.Build();
try {
var response = await client.Voice.APIController.GetCallTranscriptionAsync({ACCOUNT_ID}, {CALL_ID}, {RECORDING_ID});
Console.WriteLine(response.Data);
} catch (ApiException e) {
Console.WriteLine(e.Message);
}
}
require 'bandwidth-sdk'
begin
BW_USERNAME = ENV.fetch('BW_USERNAME')
BW_PASSWORD = ENV.fetch('BW_PASSWORD')
BW_ACCOUNT_ID = ENV.fetch('BW_ACCOUNT_ID')
CALL_ID = ENV.fetch('CALL_ID')
RECORDING_ID = ENV.fetch('RECORDING_ID')
rescue
p 'Please set the environmental variables defined in the README'
exit(-1)
end
Bandwidth.configure do |config|
config.username = BW_USERNAME
config.password = BW_PASSWORD
end
recordings_api_instance = Bandwidth::RecordingsApi.new
body = Bandwidth::TranscribeRecording.new(callback_url: 'http://example.test/transcription')
begin
response = recordings_api_instance.get_call_transcription(BW_ACCOUNT_ID, CALL_ID, RECORDING_ID)
p response.transcripts
rescue Bandwidth::ApiError => e
p e.code
end
import { RecordingsApi, Configuration } from 'bandwidth-sdk';
const BW_USERNAME = process.env.BW_USERNAME;
const BW_PASSWORD = process.env.BW_PASSWORD;
const BW_ACCOUNT_ID = process.env.BW_ACCOUNT_ID;
const config = new Configuration({
BW_USERNAME,
BW_PASSWORD
});
const recordingsApi = new RecordingsApi(config);
const callId = 'c-abc12345-6defabc1-2345-6def-abc1-23456defabc1';
const recordingId = 'r-abc12345-6def-abc1-2345-6defabc12345';
const { status, data } = await recordingsApi.getCallTranscription(
BW_ACCOUNT_ID,
callId,
recordingId
);
import os
import bandwidth
from pprint import pprint
configuration = bandwidth.Configuration(
username=os.environ["BW_USERNAME"],
password=os.environ["BW_PASSWORD"]
)
with bandwidth.ApiClient(configuration) as api_client:
api_instance = bandwidth.RecordingsApi(api_client)
account_id = os.environ["BW_ACCOUNT_ID"]
call_id = { CALL_ID }
recording_id = { RECORDING_ID }
try:
api_response = api_instance.get_call_transcription(account_id, call_id, recording_id)
print("The response of RecordingsApi->get_call_transcription:\n")
pprint(api_response)
except Exception as e:
print("Exception when calling RecordingsApi->get_call_transcription: %s\n" % e)
<?php
require "vendor/autoload.php";
$config = new BandwidthLib\Configuration(
array(
'voiceBasicAuthUserName' => {BW_USERNAME},
'voiceBasicAuthPassword' => {BW_PASSWORD},
)
);
$client = new BandwidthLib\BandwidthClient($config);
$voiceClient = $client->getVoice()->getClient();
try {
$response = $voiceClient->getCallTranscription({ACCOUNT_ID}, {CALL_ID}, {RECORDING_ID});
print_r($response->getResult()->transcripts);
} catch (BandwidthLib\APIException $e) {
print_r($e->getResponseCode());
}
In this example, using your callId
and recordingId
you are requesting to download a specific transcription. Similar to requesting a recording, you can use this to download as many transcriptions as you require.
Where to next?
Now that you have learnt how to record and transcribe calls, check out some of the available actions in the following guides: