---
schema_version: "1"
id: c01c67dfae5e54e320934229329a85e9c437abcb13bdd3ac35f27f9e877249a0
title: Introducing the Salesforce Shield Platform Encryption REST API
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/platform/api-rest-encryption/guides/api-rest-encryption.md
canonical_url: https://developer.salesforce.com/docs/platform/api-rest-encryption/guide/api-rest-encryption.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 94d8a4230a94efb9e599207d55a28fa0e17e019bc450b186fb93f723845dfa31
products:
  - Platform Encryption REST API Developer Guide
  - Platform Developer Content
---

# Introducing the Salesforce Shield Platform Encryption REST API

The Salesforce Shield Platform Encryption API enables you to bring your own key (BYOK)—that is, to control your own tenant secrets on your own premises. Use the POST, GET, and PUT operations to create your tenant secrets, import them into Salesforce, and rotate them as needed. The Encryption REST API is available in API versions 38.0 and later.

The API provides powerful and simple web services for interacting with Lightning Platform. This API is customized for use with Shield Platform Encryption features and gives you easy access to the special objects and functionality it provides.

## Getting Started

**note:** If you plan to work with many records, you may also need the [Bulk API](https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/asynch_api_intro.htm). Using Bulk API 2.0 or Bulk API requires basic familiarity with software development, web services, and the Salesforce user interface. Because both Bulk APIs are asynchronous, Salesforce doesn’t guarantee a service level agreement.

To get set up to use the Salesforce REST API, see the [REST API Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_rest.htm). The guide explains the API’s characteristics and architecture and how to set up your development environment.

Run some sample REST requests in your development org to learn the API basics. Trying out the examples now makes it easier to build your applications later.

Start with a development platform with authorization set up on it. The REST API client needs a valid `sessionId` to use. If you don’t have a platform, see the [REST API Developers Guide](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/) for information about creating one.

**note:** To use the encryption API calls, you must have the Manage Encryption Keys permission and have Shield Platform Encryption enabled in your org. If you don’t have both, nothing is returned.

The Encryption API isn’t part of the regular Lightning Platform REST API. It’s available with the Salesforce Shield or Shield Platform Encryption add-on licenses.

**See Also**

- [Authorization Through Connected Apps and OAuth 2.0](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_understanding_authentication.htm)

### Use the Platform Encryption API

Use the Platform Encryption API to manage tenant secrets. You can complete most key management and auditing tasks via the API that you can do in the user interface.

## Set Up Your REST Client

To work through these examples, we'll use Python to prepare a Simple Salesforce REST API client.

To initialize a Simple Salesforce REST API client named `sf`, use this sample code to create a Salesforce instance called `sf`.

```nolang
from simple_salesforce import Salesforce
URL ='https://{SF_SERVER}/services/Soap/u/37.0'
sf = Salesforce(session_id={sessionId}, instance_url=URL, version='44.0')
```

Now you can use the Salesforce instance `sf` to issue REST API calls, like this:

```nolang
sf.restful({TS_URL}, {request_params}, method = ‘GET’|'POST'|’PATCH’|’DELETE’)
```

Or you can use the equivalent calls provided by the Simple Salesforce module, like this:

```nolang
sf.TenantSecret.[get|create|update]({parameters})
```

## Create a Tenant Secret

Use the POST method to create a tenant secret. Usually, you can create one tenant secret every 24 hours in production orgs, and once every 4 hours in sandbox orgs. You can generate tenant secrets for the Search Index and Event Bus types once every 7 days.

- Use the POST method to create a tenant secret, using the TenantSecret specific URL.

  ```nolang
  # extract TenantSecret endpoint URL, e.g.
  # https://myorg.salesforce.com/services/data/v44.0/sobjects/TenantSecret/
  TS_URL = sf.TenantSecret.base_url
  ```

- To generate a new tenant secret, use a REST POST command, without parameters.

  ```nolang
  sf.restful(TS_URL, {}, method = 'POST')
  ```

- Or use the Simple Salesforce equivalent.

  ```nolang
  sf.TenantSecret.create({'Type':"SearchIndex"})
  ```

  Tenant secrets default to the Data in Salesforce type. Tenant secrets of this type encrypt data in fields, attachments, and files other than search index files. Specify a `Type` other than `Data` if you want to use a different type of tenant secret. For more information, see [Shield Platform Encryption Key Material Types](https://help.salesforce.com/s/articleView?id=xcloud.security_pe_ts_types.htm&type=5) in Salesforce Help or the [TenantSecret](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_tenantsecret.htm#!) entry in the API Object Reference Guide.

The complete response contains an ordered dictionary that looks like this:

```nolang
[ (u'id', u'02G41000000HLXrEAO'), (u'success', True), (u'errors', []) ]
```

You can also use the POST method to create a callout connection that fetches a cache-only key tenant secret from a key service outside of Salesforce.

- Make sure that Bring Your Own Key (BYOK) is enabled in your org. Then turn on Allow Cache-Only Keys with BYOK from the Advanced Settings page in Setup.
- Create a certificate that’s compatible with customer-supplied key material. See [Generate a BYOK-Compatible Certificate](https://help.salesforce.com/s/articleView?id=xcloud.security_pe_byok_generate_cert.htm&type=5) in Salesforce Help.
- [Create and assemble your key material](https://help.salesforce.com/s/articleView?id=xcloud.security_pe_byok_cache_create.htm&type=5).
- Create a named credential to serve as your authenticated callout mechanism. You can define your named credential through Setup or directly with Apex. Specify a BYOK-compatible certificate and an HTTPS endpoint.
- Configure the connection to your remote key service. This connection uses a named credential and its associated certificate to fetch a specified cache-only key tenant secret.

  ```apex
  remote_params = { ‘Source’: ‘Remote’,
  ‘RemoteKeyIdentifier’: ...,
  ‘RemoteKeyServiceId': ...,
  ‘RemoteKeyCertificate’: ...}

  sf.TenantSecret.create(remote_params)

  ```

## Upload a Tenant Secret

Use the POST method to upload a tenant secret to your org.

1.  Find your tenant secret's encrypted form, hash and the name of the BYOK-specific certificate name used to encrypt the plain text form of the original tenant secret.

    (The original tenant secret is never sent to Salesforce.)

    Here's a sample of code you might use to get this information.

    ```nolang
     ### reading encrypted secret and secret hash from files.
    with open("encrypted_secret.b64") as f:
    encrypted_secret = f.read().translate(None, '\n')
    with open("plaintext_secret_hash.b64") as f:
    secret_hash=f.read().translate(None, '\n')
    # select certificate name
    Cert_name = “MyActivePECertificate”
    ```

2.  Upload your tenant secret by sending a POST call specifying the encrypted secret, secret hash, and certificate name.

    ```nolang
    sf.TenantSecret.create({
    'SecretValue':encrypted_secret,
    'SecretValueHash':secret_hash,
    'SecretValueCertificate':cert_name })
    ```

The actual parameters for this create request will look like this:

```nolang
sf.TenantSecret.create({
'SecretValue':'Zk/xUSIkqKNYKoiZoidet4UQkNc3Q9H3Wxf6+fxbqbtfBdp2If5DHbGjy9pe9xRx18tiXzw77u1Dwa4suHgk1je1EfH0Nh0WDZw
BLkgJDOTsw4j7mwxYWmbfjOqz4Lix8gk9WSstJPwxwvASPyJ/XttTqeMQSkh03BLBlghRkB40YY57QIfnrHPnLUvIcMwVm0fmYtCHMvfsvNtcpgPgs
WMQTQ9WuBnmqgeq+94+NDtg4kFLMDqPUdSd19KI0KOXTedy2XldLBI72A/6C7Qb7xBdNrtlXJVqZEI/nQ8wluVWIhh7ZN/tsPjtFJ6k3iFuv1FTzTX
dRZJ1icOSfOTyHVWbMpgUS/V2+AR2MV2SgtPOWrd7GIyqKQC0Ohveh/Hiz0H1VwnJIH6Wupjuf4Ocdt/XkjEcqYfp6vLnbQ8mGRUrTPfNXz14I1XfA
iU2BdfNlkRXOe1iVMMBDV/MPM5jTXyHCdD1TKDmSR7O3q/HNUeqUvOJVjSd3MclNdLo9SjEdS9/liMX8juk7dxht1GfJ3c4E41upyZtRxmhf7lFEIr
okpLixqTb0vpUhTRzzHHgb5PI6XiZM4DFLaXw6tj12B9ZFRo/jxpEOUzRtbVYqjbJEhoSq+XkxfId0PAwn+/0EL7/5YxQk9uy69T5nDPOospmt+/6W
XNjUHPIqGQ1+4s=' ,
'SecretValueHash':'hhAJ7E7Zn6sfQKvHbm+JiAz/WDPHnFSMmfkEXxkc2Qs=',
'SecretValueCertificate':’MyActivePECertificate’ })
```

## Retrieve a Tenant Secret

Use the GET method to read information about a tenant secret that's been uploaded to your org.

Retrieve all the available information about your tenant secret by sending a GET command specifying the tenant secret ID.

**tip:** A tenant secret ID looks like this: `u'02G41000000HLXrEAO'`

```nolang
  sf.TenantSecret.get(tenant_secret_id)
```

All attributes of the tenant secret are returned in a JSON dictionary that looks like this:

```nolang
  ([
     (u'attributes',
     OrderedDict([
     (u'type', u'TenantSecret'),
     (u'url', u'/services/data/v37.0/sobjects/TenantSecret/02G41000000HLXrEAO')])),
     (u'Id', u'02G41000000HLXrEAO'),
     (u'IsDeleted', False),
     (u'CreatedDate', u'2016-09-09T08:21:50.000+0000'),
     (u'CreatedById', u'00541000000IQT3AAO'),
     (u'LastModifiedDate', u'2016-09-09T08:21:50.000+0000'),
     (u'LastModifiedById', u'00541000000IQT3AAO'),
     (u'SystemModstamp', u'2016-09-09T08:21:50.000+0000'),
     (u'Description', None),
     (u'SecretValue',
  u'CgMyMDISEPrWDhfoajtUkEKAkO1/bDwaMIqgtRHI0ft+zVbkIzrQBcjZ8XUvgxUvTZiyXnNIIC04iRAyr57R8/DdY8UUZy1MbA=='),
     (u'Version', 1),
     (u'Status', u'Active')
  ])

```

## Export a Tenant Secret

Use the GET method to export a tenant secret to a file.

1.  Export your tenant secret by sending a GET command specifying the ID of the secret and the secret value, in its encrypted form.

    ```nolang
    exportedString = sf.TenantSecret.get(tenant_secret_id)['SecretValue']
    ```

    The secret is written out to a file that looks like this:

    ```nolang
    'CgMyMDISEPrWDhfoajtUkEKAkO1/bDwaMIqgtRHI0ft+zVbkIzrQBcjZ8XUvgxUvTZiyXnNIIC04iRAyr57R8/DdY8UUZy1MbA=='

    ```

2.  Save this in case you want to re-import your secret.

    ```nolang
    # export encrypted tenant secret to a file
    with open('exported-TenantSecret001.txt', 'wb') as f:
    f.write(exportedString)
    ```

## Destroy a Tenant Secret

You can use the PATCH method to destroy a tenant secret when you are certain you don’t need it.

(Technically, you can't really destroy a tenant secret. Instead, you update it with an empty value or change its status.)

**important:** After you destroy a tenant secret, related data is not accessible unless you reimport a previously exported secret.

In version 43.0 and earlier, destroy a tenant secret by passing in the SecretValue with an empty string.

```nolang
sf.TenantSecret.update(tid, {"SecretValue":""})
```

In version 44.0 and later, destroy a tenant secret by passing in the new `Status` value instead of a `SecretValue`.

```nolang
sf.TenantSecret.update(tid, {"Status":"Destroyed"})
```

**note:** You can change a Salesforce-generated or customer-supplied tenant secret’s `Status` from Archived to Destroyed or Destroyed to Archived.

In version 44.0 and later, you can change the `Status` of the most recent version of a cache-only key tenant secret from Destroyed to Active or Active to Destroyed. For example, if you have two versions of a cache-only key tenant secret, you can update version 2 but not version 1.

The secret is destroyed, but its hash is preserved to support validation in case you need to reimport a copy of the secret.

## Import a Tenant Secret

You can reimport an HSM or customer-supplied tenant secret that you have exported using the PATCH method. If you use the Cache-Only Key Service, you can reactivate a cache-only key tenant secret instead of importing it.

In API version 43.0 and earlier, import an HSM or customer-supplied tenant secret by passing in the SecretValue with the string you saved when you exported the tenant secret.

```nolang
# read exported secret from file
with open('exported-TenantSecret001.txt',) as f:
f.read(exportedString)

sf.TenantSecret.update(tenant_secret_id, {"SecretValue":exportedString})

```

In API version 44.0 and later, import an HSM or customer-supplied tenant secret by passing in the new Status along with the SecretValue.

```nolang
# read exported secret from file
with open('exported-TenantSecret001.txt',) as f:
f.read(exportedString)

sf.TenantSecret.update(tenant_secret_id, {"Status":"Archived", "SecretValue":exportedString})

```

You can’t import cache-only tenant secrets, but you can reactivate them. To reactivate a cache-only key tenant secret, update its Status without referencing the SecretValue.

```nolang
sf.TenantSecret.update(tenant_secret_id, {"Status":"Archived"})
```

You can reactivate cache-only tenant secret in versions 44.0 and later.

**note:** You can change a Salesforce-generated or customer-supplied tenant secret’s `Status` from Archived to Destroyed or Destroyed to Archived.

In version 44.0 and later, you can change the `Status` of the most recent version of a cache-only key tenant secret from Destroyed to Active or Active to Destroyed. For example, if you have two versions of a cache-only key tenant secret, you can update version 2 but not version 1.
