---
"@context": https://schema.org
"@type": TechArticle
"@id": https://www.twilio.com/docs/voice/tutorials/voice-recording-encryption#article
headline: Voice recording encryption
description: Learn to encrypt Twilio Voice recordings using RSA public keys for secure self-service automation, contact centers, and AI/ML transcription in Java, JS, Python, and C#.
url: https://www.twilio.com/docs/voice/tutorials/voice-recording-encryption
inLanguage: en
dateModified: 2026-08-19T18:30:57.000Z
author:
  "@type": Organization
  name: Twilio Developer Education Team
publisher:
  "@type": Organization
  name: Twilio
---

# Voice recording encryption

Learn to secure your Twilio Programmable Voice recordings by using hybrid encryption. To do this, you'll generate an RSA key pair, upload your public key to Twilio, and configure your account to automatically encrypt new recordings.

You can use this guide to create self-service automation, inbound and outbound contact centers, and AI/ML transcription.

See [Related reference documentation](#related-reference-documentation) to learn more about the public key and recording resources used in this guide.

[All Advanced Programmable Voice features guides](/docs/voice/guides/by-feature-product#advanced-programmable-voice-features)

> \[!WARNING]
>
> After you activate the Voice Recording Encryption feature, only **you** will be able to decrypt the recordings. There is no one at Twilio, including Twilio support, that will be able to decrypt your recordings. Therefore testing of this feature should only be done on **test** accounts with non-production recordings.

## How Voice Recording Encryption works

Today, by default, all Programmable Voice Recordings are encrypted at rest while stored in Twilio's cloud storage. With Voice Recording Encryption enabled, your recordings are encrypted with your public key as soon as the call ends, while the recording is within the Twilio infrastructure, and before it is in cloud storage. The recording remains in this encrypted state until you retrieve it, ensuring that the recording can only be accessed by you, the holder of the corresponding private key.

The Voice Recording Encryption feature is implemented using [hybrid encryption](https://en.wikipedia.org/wiki/Hybrid_cryptosystem). The following are the summarized set of steps of encryption/decryption for each recording.

### Twilio encryption steps

1. Twilio generates a random Content Encryption Key (CEK) for each recording.
2. Twilio encrypts the recording content with the generated CEK using the [AES256-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode) cipher.
3. Twilio encrypts the CEK with the customer's public key using the RSAES-OAEP-SHA256-MGF1 cipher.

### Customer decryption steps

1. Customer retrieves the CEK and Initial Vector (IV) encryption values for the recording.
2. Customer decrypts the CEK using their private key.
3. Customer decrypts the recording content using the CEK, along with the IV encryption value.

Detailed decryption steps and code samples can be found [later in this guide](#decrypting-your-recordings).

## Configuring Voice Recording Encryption

### Step 1: Generate a RSA key pair

First, generate an RSA public/private key pair. There are many different ways to do this, we recommend using [openssl](https://www.openssl.org/). Once you have openssl installed, you can generate a 2048 length private key with this command:

```bash
openssl genrsa -out private_key.pem 2048
```

The generated file, `private_key.pem`, contains your private key, which will look something like this:

```bash
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAtePBUk3IM45Jj8eFFrmwzjr/2seEtMknl5OD7VDBipazsq5v
MBnIYcE+EuzDiFC5XXww9rncFRZC0I3hLUejUTkJNZjMDQzVFkGXo9+A4MsXRZqK
OOYhCNAr2C1acpHKK6bEqGhRW2F2R0dSndbEKOCpPKD70ZF2aZyQdb//9104ROdh
bvsycQD7ZGQ8V5SoUo6kPBjQv1sbi99LN6uQm+trUDHkBhbpeKU836YPpIH1ZAqG
h2sSzRHN0eXdOPYNdu649ZuOSz0kIUN22e8R39suRhu6VbrC2kvVz2Su+tSPMWlp
gKjMboVKrsWUH9B1fQM9ajixc8fc892ZoGBqaQIDAQABAoIBAQCd5BlbEr4pUui0
cOQs+ABs5XZYOj4OmVdPEvTAuwtm/K78+sL2JEt34EG8N978o+ZlKntukaRkgbB6
Tc8ceUViKnq+Fed7pJoM+d9il4/Okz2eZCp8ffhLKDoHLEeJkNjIz7mC3xtQkegU
s+sZrOcW/P6r7KrsHrOFti0IqiTOWps1M6gIUKFWcIRIh/6SyN0gmdDxmfGD9o4W
CePswAS0fmwMZPCwQ9GazC8iVL+CvrF92UNfmNQSUiuR0GynOlsMnDu2GvSim3yO
9lqWAo1yyEBVU8x6pS1wFTdsXQ7Ch2Ei9ZU+XE6SL5lq3jSc8WqIGmLvZ+zw5eAR
8J73+fkBAoGBAO12zPHKgvN5nHRTrO3gNVcl92201umLHllf2elOjlE98/qtNsuX
R96LILDv4rgSjwH0+eVQW2g2B5o3D6KPvXdEvUmaRIXDValqr1UzED1DFWLs1MQK
HO30rJSpfWpTD3B56zvMb620avIBv3+Oe6kmjImn7Db/nyuEZrs49sE5AoGBAMQW
bAXgbG5GDUMVvJfrWwiXz3Ip7yv2j6xz5MtU58gytVV2ZnesLSCfpKrUpalPDWsX
04ZBuZ7bqZR4UpGQnGlYePtttKMdI4Vbo+tPK8gNN8ELu+8Fgmr0UNv3BWmcSRzo
AfiWWIHZS6iAkPoaYWQtCtf3WU0wnt/beiP/NWKxAoGAafCUYlLMtT7OE/+4qK9c
XLLtfh4tuyd7tLfUigen6orPLEjWp2GoiJpdTVLYPPLapi7axflhrk5ceeqSqR2j
k3AxWoLeiyaoMtsLueD8H7ir8+Rgz80LNwXvcKtk7mh7/NwHnDgKot5Yz/sDqi6w
8Lfn/wnRkn/cTRfWlTRGsdECgYEAuXjP4lsdlMyT3MFhqnzGlYEqibyaaoYD7cWN
Qrpjplw4YsbkMwvbf4EhOyh6LYQFmCdoPxRJ47W4WCPbTa5wE8DIZmGlO6fjIk/E
41z2d3nxI5rav0IB0vKWzQiAyR03lqzouF5VBzUmuBIrjzWGqz9jg1WF1VpI3Er3
47aQo3ECgYBQ7UZ3IP1+unprNsvVDT4CbjsoAypstmQhfgxYiNPY0wB7rvTOWT3q
3vwOBwVBjfvkG8yYglYgHc0xGOrqL6DxhMUFTxBe0iDvBX0QM1tpp4apsKdHvuuQ
h1icaQZp8WKxBOzVilj3DLoHJEyIrsWWMnDHazV4fxbxijpj4uwJCw==
-----END RSA PRIVATE KEY-----
```

> \[!NOTE]
>
> If your particular project/cryptography library requires [PKCS8 syntax,](https://en.wikipedia.org/wiki/PKCS_8) you can convert your private key to PKCS #8 format by executing the following:
>
> ```bash
> openssl pkcs8 -in private_key.pem -topk8 -nocrypt -out private_key_pkcs8.pem
>
> ```
>
> You will need to do this for our [Java Decryption Tool](https://github.com/TwilioDevEd/encrypted-media-recordings/blob/master/voice-recordings-decryptor/java/RecordingsDecryptor.java) and our [JavaScript Decryption](https://github.com/TwilioDevEd/encrypted-media-recordings/blob/master/voice-recordings-decryptor/javascript/RecordingsDecryptor.html) Tool.

> \[!WARNING]
>
> It is your responsibility to keep your private key safe. Losing your private key means that you will not be able to decrypt any of the files that were encrypted with the corresponding public key.

You can obtain the public key by executing the following command:

```bash
openssl rsa -in private_key.pem -pubout -out public_key.pem
```

The file `public_key.pem` contains the public key. It should look something like this:

```bash
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtePBUk3IM45Jj8eFFrmw
zjr/2seEtMknl5OD7VDBipazsq5vMBnIYcE+EuzDiFC5XXww9rncFRZC0I3hLUej
UTkJNZjMDQzVFkGXo9+A4MsXRZqKOOYhCNAr2C1acpHKK6bEqGhRW2F2R0dSndbE
KOCpPKD70ZF2aZyQdb//9104ROdhbvsycQD7ZGQ8V5SoUo6kPBjQv1sbi99LN6uQ
m+trUDHkBhbpeKU836YPpIH1ZAqGh2sSzRHN0eXdOPYNdu649ZuOSz0kIUN22e8R
39suRhu6VbrC2kvVz2Su+tSPMWlpgKjMboVKrsWUH9B1fQM9ajixc8fc892ZoGBq
aQIDAQAB
-----END PUBLIC KEY-----
```

In the next step, you will configure Twilio with this public key.

### Step 2: Create a Twilio Public Key resource

After you have the RSA public key, create a Twilio Public Key resource that contains your public key. You can do this with the [Public Key Resource REST API](/docs/iam/credentialpublickey-resource) or in the Twilio Console.

## Twilio Console

1. In [Twilio Console](https://1console.twilio.com), go to **Voice** > **Recordings** > **Settings**.
2. In the **Voice Recording encryption** section, select **Create new public key**.
3. Enter a **Friendly name** for your public key.
4. Copy the full contents of the `public_key.pem` file generated in [step 1](#step-1-generate-a-rsa-key-pair)—including the `BEGIN PUBLIC KEY` and `END PUBLIC KEY` lines—and paste it into the **Public key** field.
5. Select **Create**.

## Legacy Console

1. In the [legacy Console](https://www.twilio.com/console/runtime/credentials), go to **Runtime** > **Credentials**.
2. Select **Create new Credential**.
3. Provide a friendly name for your public key.
4. Copy the full contents of the `public_key.pem` file generated in [step 1](#step-1-generate-a-rsa-key-pair)—including the `BEGIN PUBLIC KEY` and `END PUBLIC KEY` lines—and paste it into the **PUBLIC KEY** field.
5. Select **Create**.

> \[!WARNING]
>
> After you submit the Twilio Public Key resource, the public key itself can no longer be retrieved from Twilio. All future references to this public key use a SID in the form `CRxx`.

### Step 3: Turn on Voice Recording encryption

Turn on Voice Recording encryption at a project or subaccount level and select the public key you created in [step 2](#step-2-create-a-twilio-public-key-resource). For the procedure, see [Turn on Voice Recording encryption](/docs/voice/recording-settings#turn-on-voice-recording-encryption).

After you save your settings, Twilio encrypts all new Recordings on this account with the configured public key.

## Decrypting Your Recordings

### Step 4: Retrieve recording specific encryption details

Obtain the `public_key_sid`, `encrypted_cek`, and `iv` parameters within `EncryptionDetails` JSON object, which you can retrieved by making an HTTP `GET` request to the Recordings resource. The `EncryptionDetails` data will also be posted to your RecordingStatusCallback.

`EncryptionDetails` includes relevant encryption details if the recording was encrypted with the Voice Recording Encryption feature. It will be `null` if the recording was not encrypted. The parameters within EncryptionDetails include :

| Parameters       | Description                                                                                                 |
| ---------------- | ----------------------------------------------------------------------------------------------------------- |
| `type`           | The type of encryption. Currently, the only value supported is *rsa-aes*.                                   |
| `public_key_sid` | A 34-character string that uniquely identifies the public key resource used as by the recording encryption. |
| `encrypted_cek`  | Base64-encoded Content Encryption Key (CEK) used as part of recording encryption.                           |
| `iv`             | Base64-encoded randomly generated Initial Vector (IV) used as part of recording encryption.                 |

### Make a GET request

Any recording encrypted with Voice Recording Encryption will contain additional encryption properties on the recording resource. See the request/response example below to query the recording resource metadata.

The request:

Fetch a Recording

```bash
curl -X GET "https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/Recordings/REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.json" \
-u $TWILIO_API_KEY:$TWILIO_API_SECRET
```

```json
{
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "api_version": "2010-04-01",
  "call_sid": "CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "conference_sid": "CFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "channels": 1,
  "date_created": "Fri, 14 Oct 2016 21:56:34 +0000",
  "date_updated": "Fri, 14 Oct 2016 21:56:38 +0000",
  "start_time": "Fri, 14 Oct 2016 21:56:34 +0000",
  "price": "-0.00250",
  "price_unit": "USD",
  "duration": "4",
  "sid": "REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "source": "StartConferenceRecordingAPI",
  "status": "completed",
  "error_code": null,
  "uri": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings/REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.json",
  "subresource_uris": {
    "add_on_results": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings/REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/AddOnResults.json",
    "transcriptions": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings/REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Transcriptions.json"
  },
  "encryption_details": {
    "encryption_public_key_sid": "CRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "encryption_cek": "OV4h6zrsxMIW7h0Zfqwfn6TI2GCNl54KALlg8wn8YB8KYZhXt6HlgvBWAmQTlfYVeLWydMiCewY0YkDDT1xmNe5huEo9vjuKBS5OmYK4CZkSx1NVv3XOGrZHpd2Pl/5WJHVhUK//AUO87uh5qnUP2E0KoLh1nyCLeGcEkXU0RfpPn/6nxjof/n6m6OzZOyeIRK4Oed5+rEtjqFDfqT0EVKjs6JAxv+f0DCc1xYRHl2yV8bahUPVKs+bHYdy4PVszFKa76M/Uae4jFA9Lv233JqWcxj+K2UoghuGhAFbV/JQIIswY2CBYI8JlVSifSqNEl9vvsTJ8bkVMm3MKbG2P7Q==",
    "encryption_iv": "8I2hhNIYNTrwxfHk"
  },
  "media_url": "http://api.twilio.com/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings/REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
```

### RecordingStatusCallback

RecordingStatusCallback is the reliable way to receive webhooks for completed or failed recordings. See this [RecordingStatusCallback support article](https://help.twilio.com/hc/en-us/articles/360014251313-Getting-Started-with-Recording-Status-Callbacks) for more details.

Subscribe to 'failed' RecordingStatusCallbackEvent to receive callbacks in recording encryption failure scenarios; these are described [later in this article](#failure-scenarios).

Here is an example of a RecordingStatusCallback webhook with encryption parameters:

```bash
"RecordingSource": "OutboundAPI"
"EncryptionDetails": "{"type":"rsa-aes","public_key_sid":"CR201607f4ca45a533cdca8d9a828c2a87","encrypted_cek":"ZriXxBEXSywEohXQZV53KGvyzAO1HpKRxCuMo/pcKiT7C+bWKfelZuX0eW1jb7iGcESrOqwvLo4v4GVRPDdJKsaO6R/AVTDcA+he5syPDBgg20ECilAhC/9/CNxfbIuQD+rRKmx0O7SOJJyazbc4zlv+4ClWwDm6g/8z0ekpYs/tNrlQenbxU/Un9uLeeBaJtFKeK5YSUea5n3Kce22iaPZMy3WUGBg+JfOHrccvCjDjX5QQ21I3rcdpgb5nwpzf3MQwmExhW8SJtmQ1cL4jDeKojM255HhhcgOYDwcyrTfY7svUkqNrEKei1q5ZFdBl+SjjKfSdE0BgEvTceZZYrQ==","iv":"7MiadYE7QDgVSRm9"}"
"RecordingSid": "REb719a56ceca43b2d06967983570e658a"
"RecordingUrl": "https://api.twilio.com/2010-04-01/Accounts/AC18d5c6f2003e8710de63b2f9c412b145/Recordings/REb719a56ceca43b2d06967983570e658a"
"RecordingStatus": "completed"
"RecordingChannels": "1"
"ErrorCode": "0"
"CallSid": "CA5987df4d600665d67f53e1bd4cec76d6"
"RecordingStartTime": "Tue, 28 May 2019 02:18:02 +0000"
"AccountSid": "AC18d5c6f2003e8710de63b2f9c412b145"
"RecordingDuration": "5"
```

### Step 5: Decrypt using private key and encryption parameters

1. Retrieve customer private key corresponding to `public_key_sid` and use it to decrypt the base64-encoded `encrypted_cek` from your retrieved `EncryptionDetails` object.
2. Use the decrypted CEK and the base 64-encoded `iv` from your retrieved `EncryptionDetails` object to initialize an AES256-GCM SecretKey object.
3. Decrypt the encrypted recording using the SecretKey.

> \[!NOTE]
>
> If you are using a decryption tool that requires the authentication tag, this tag is returned in the last 16 bytes of the ciphertext.

To help you with your own code, here are some decryption code samples in key languages:

* [Java](https://github.com/TwilioDevEd/encrypted-media-recordings/blob/master/voice-recordings-decryptor/java/RecordingsDecryptor.java)

  * **Note:** Your private key must be in PKCS8 format for this tool.
* [JavaScript](https://github.com/TwilioDevEd/encrypted-media-recordings/blob/master/voice-recordings-decryptor/javascript/RecordingsDecryptor.html)

  * **Note:** Your private key must be in PKCS8 format for this tool.
* [Python](https://github.com/TwilioDevEd/encrypted-media-recordings/blob/master/voice-recordings-decryptor/python/RecordingsDecryptor.py)
* [C#](https://github.com/TwilioDevEd/encrypted-media-recordings/blob/master/voice-recordings-decryptor/c%23/RecordingsDecryptor.cs)

## Failure scenarios

**Voice Recording Encryption is enabled but Twilio is unable to determine or retrieve the public key configured for recording encryption**

* The account's most recently added retrievable public key, if one exists, will be used for encryption.
* The `public_key_sid` within `EncryptionDetails` will represent the `SID` of the public key used for encryption, which is not necessarily the one added to the account.
* A notification will be sent to the account. The notification is viewable from the [Debugger in the Console](https://www.twilio.com/console/runtime/debugger). It indicates that an alternative public key was used.

**Twilio is unable to encrypt the recording because there aren't any public keys on the account or an intermittent system issue occurred.**

* The recording file is deleted and will not be available for access.
* Recording resource metadata will have a `Status` of `failed`, an `ErrorCode` of `16104`, and an `EncryptionDetails` that is `null`.
* A RecordingStatusCallback will be sent, if configured via RecordingStatusCallbackEvent, with a `Status` of `failed`, and an `ErrorCode` of `16104`. `EncryptionDetails` is not included in the callback.
* A notification will be sent to the account. The notification is viewable from the [Debugger in the Console](https://www.twilio.com/console/runtime/debugger). It indicates a failure was due to inaccessibility of public keys or an internal system error.

## Use cases for voice recording encryption with Twilio Programmable Voice

This guide teaches the basics required for the following use cases:

### Create self-service automation with Twilio Programmable Voice

Ensure that sensitive data captured during automated interactions—such as account details or personal information—is encrypted immediately. This allows you to build secure IVR systems that meet strict data privacy requirements.

To learn more advanced features that you can use with self-service automation, see [Voice self-service automation](/docs/voice/guides/self-service-automation).

### Create an inbound contact center with Twilio Programmable Voice

Protect customer privacy by encrypting inbound support calls as soon as they end. This ensures that only authorized systems with your private key can access recording files for quality assurance or compliance audits.

To learn more advanced features that you can use with inbound contact centers, see [Voice inbound contact center](/docs/voice/guides/inbound-call-center).

### Create an outbound contact center with Twilio Programmable Voice

Secure outbound communications by applying public-key encryption to all recordings made during sales or service calls. This prevents unauthorized access to recording files stored in the cloud.

To learn more advanced features that you can use with outbound contact centers, see [Voice outbound contact center](/docs/voice/guides/outbound-call-center).

### Create transcriptions for AI or ML with Twilio Programmable Voice

Safeguard raw audio data before it is processed by transcription engines. By encrypting the source recording, you maintain a secure pipeline when moving media to machine learning models for sentiment analysis or automated summarization.

To learn more advanced features that you can use with AI or ML transcription, see [Voice AI/ML transcription](/docs/voice/guides/ai-ml-transcription).

## Result

After following this guide, you have configured your Twilio account to automatically encrypt all new voice recordings using your specific RSA public key. You can confirm this is working by placing a test call, recording it, and performing a `GET` request to the Recording resource to verify that the `encryption_details` object is populated with a `public_key_sid`, `encrypted_cek`, and `iv`.

## Next steps

Explore the following guides to build on what you've learned in this guide:

* [Record phone calls](/docs/voice/tutorials/how-to-record-phone-calls): Learn the different methods to trigger recordings for your calls.
* [Secure media](/docs/voice/api/secure-media): Explore how to further secure your media streams and recordings.
* [Answering machine detection FAQ and best practices](/docs/voice/answering-machine-detection): Improve your outbound recording workflows by identifying when a human or a machine answers.

## Related reference documentation

Find reference documentation for the topics on this page.

* [Programmable Voice API Overview](/docs/voice/api)
* [Recordings resource](/docs/voice/api/recording-transcription)
* [Transcriptions resource](/docs/voice/api/recording)
* [TwiML™ for Programmable Voice](/docs/voice/twiml)
* [TwiML™ Voice: `<Record>`](/docs/voice/twiml/record)
* [TwiML™ Voice: `<Recording>`](/docs/voice/twiml/recording)
