Upload an Audio Recording to Storage

Plum Fuse makes it easy to generate audio recordings from phone calls. Using the Call Recording module you can record specific segments of a phone call or simply record all audio that occurs during a call. Using the Record module you can record specific caller input, similar to voicemail.

Regardless of how you utilize Fuse's call recording capabilities, the question of how to save those recordings remains.

For security and compliance reasons, Fuse does not save any recording data. All recordings are the client's responsibility and, therefore, are held in temporary memory until the call disconnects. At that point, the audio recording gets erased.

If you want to save one or more audio recordings made during a phone call, you must send the recorded audio to your own web server. Once the audio is on your web server, you can do anything with it you want to do.

In short, the basic workflow for call recording is as follows:

  • Fuse captures call audio.

  • Client uses a REST module to send audio to their web server.

    • This step repeats within a given call if you're capturing more than one continuous recording during a call. (See Reminder below)

  • Fuse disconnects the call and deletes all call recording data generated during that call.

  • Your call recording now resides on your web server.

Uploading Call Recording to Your Web Server

The example below outlines the entire process in simplified terms. It shows how you can collect a call recording, save it via REST API to Amazon S3, and use the file URL returned by the API in an e-mail module. The primary steps are as follows:

  • A Menu module prompts the caller to take action; the caller makes a selection.

  • The call recording ends.

  • A REST module uploads the audio file to the client's web server.

Note: If you anticipate the caller hanging up before they get to the end of the call-flow, send the generated audio file using a post-call web service instead of a REST module.

Uploading from Your Web Server to Cloud Storage

Once your audio recording gets uploaded to your web server, you can do whatever you want with the audio file(s). If you want to upload call recording audio from your web server to storage, you can use the SDK for your cloud servers or modify the following PHP sample code to run on your web server so it works with your system(s).

Sample Code

$S3_CONFIG = [
    'key' => '<aws key>',
    'secret' => '<aws secret key>',
    'region' => '<aws region>',
    'bucket' => '<aws bucket name>'

header('Content-Type: application/json');
if(isset($_POST["filename"]) && isset($_FILES)) {
	$result = upload_file($S3_CONFIG, $_FILES['recording']['tmp_name'], $_POST["filename"].".wav");
else {
	echo json_encode(array("status"=>"failure"));

function upload_file($config, $filepath, $new_name) {
    $retval = [];
    $ch = null;

    try {
        $service = 's3';
        $content_type = 'audio/wav';
        $filename = $new_name;
        $file = file_get_contents($filepath);
        $host = $config['bucket'] . ".$service." . $config['region'] . '.amazonaws.com';
        $timestamp = gmDate("Ymd\THis\Z"); // Amazon web stamp format
        $date = gmDate('Ymd');

        // HTTP request headers as key & value
        $request_headers = [];
        $request_headers['Content-Type'] = $content_type;
        $request_headers['Date'] = $timestamp;
        $request_headers['Host'] = $host;
        $request_headers['x-amz-content-sha256'] = hash('sha256', $file);
        // Sort it in ascending order

        $canonical_headers = [];
        foreach($request_headers as $key => $value) {
            $canonical_headers[] = strtolower($key) . ":" . $value;
        $canonical_headers = implode("\n", $canonical_headers);

        // Signed headers
        $signed_headers = [];
        foreach($request_headers as $key => $value) {
            $signed_headers[] = strtolower($key);
        $signed_headers = implode(";", $signed_headers);

        // Cannonical request
        $canonical_request = [];
        $canonical_request[] = "PUT";
        $canonical_request[] = "/" . $filename;
        $canonical_request[] = "";
        $canonical_request[] = $canonical_headers;
        $canonical_request[] = "";
        $canonical_request[] = $signed_headers;
        $canonical_request[] = hash('sha256', $file);
        $canonical_request = implode("\n", $canonical_request);
        $hashed_canonical_request = hash('sha256', $canonical_request);

        // AWS Scope
        $scope = [];
        $scope[] = $date;
        $scope[] = $config['region'];
        $scope[] = $service;
        $scope[] = "aws4_request";

        // String to sign
        $string_to_sign = [];
        $string_to_sign[] = "AWS4-HMAC-SHA256";
        $string_to_sign[] = $timestamp;
        $string_to_sign[] = implode('/', $scope);
        $string_to_sign[] = $hashed_canonical_request;
        $string_to_sign = implode("\n", $string_to_sign);

        // Signing key
        $kSecret = 'AWS4' . $config['secret'];
        $kDate = hash_hmac('sha256', $date, $kSecret, true);
        $kRegion = hash_hmac('sha256', $config['region'], $kDate, true);
        $kService = hash_hmac('sha256', $service, $kRegion, true);
        $kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);

        // Signature
        $signature = hash_hmac('sha256', $string_to_sign, $kSigning);

        // Authorization
        $authorization = [
            'Credential=' . $config['key'] . '/' . implode('/', $scope),
            'SignedHeaders=' . $signed_headers,
            'Signature=' . $signature,
        $authorization = 'AWS4-HMAC-SHA256' . ' ' . implode( ',', $authorization);

        // Curl headers
        $curl_headers = [ 'Authorization: ' . $authorization ];
        foreach($request_headers as $key => $value) {
            $curl_headers[] = $key . ": " . $value;

        $url = 'http://' . $host . '/' . $filename;
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $curl_headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
        curl_setopt($ch, CURLOPT_POSTFIELDS, $file);
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);


        $retval['status'] = 'success';
        $retval['url'] = $url;
    } catch(Exception $ex) {
        if(!empty($ch)) {
        $retval['status'] = 'fail';
        $retval['message'] = $ex->getMessage();

    return $retval;


The Call Recording module allows you to record specific sections of a call. However, if you want to record multiple, non-consecutive segments in your voice app, you need to follow the process above for each recording.

For example, if you want to record audio on the first and third pages of your Fuse app, you need to upload the recording from the first page before the recording on the third page can start. Therefore, you need to start, stop, and upload the recording on page one. Then follow the same process for page three.

Each non-contiguous segment of recorded audio needs its own REST upload.

If you intend to capture more than one separate audio file in a single call, be sure to plan for multiple REST calls to send recorded audio when building your application.

Last updated