In order to decrypt an existing encrypted document, you first define metadata that specifies the tenant ID that was used when the document was encrypted. Similar to encrypt, you must also provide the ID of the service or user that is performing the decryption and a label for the type of data being decrypted. These fields help build richer audit trails that provide more context to your customers about what data is being decrypted, by whom, and why.
The tenantId field of the provided metadata must be the same as the one specified when the data was encrypted so that the proper tenant key is used during decryption. The other metadata fields do not have to match and are only used to improve auditing.
DocumentMetadata metadata = new DocumentMetadata("TENANT_ID", "serviceOrUserId", "data label");
const metadata = new RequestMetadata("TENANT_ID", "serviceOrUserId", "data label");
$metadata = new RequestMetadata("TENANT_ID", new IclFields("serviceOrUserId", "data label"), []);
Create the encrypted document structure from the EDEK and encrypted fields that you have persisted.
String edek = /* base64 encoded EDEK from your persistence layer */;
Map<String, byte[]> encryptedFields = /* fieldname and ciphertext pairs from your persistence layer */;
EncryptedDocument recreated = new EncryptedDocument(encryptedFields, edek);
const encryptedDoc = {
    edek: /* base64 encoded EDEK from your persistence layer */,
    encryptedDocument: /* fieldname and ciphertext pairs from your persistence layer */
Now decrypt the encrypted document map and retrieve the resulting plaintext document map. The decrypt call makes a request to the Tenant Security Proxy which in turn makes a request to the tenant’s KMS to unwrap the EDEK that you’ve provided. Once the DEK has been returned to the client, it is used to decrypt the provided document bytes. The encrypted data is never transferred to the Tenant Security Proxy - all decryption happens locally within the client.
PlaintextDocument decryptedResults = client.decrypt(recreated, metadata).get();
Map<String, byte[]> decryptedDocumentMap = decryptedResults.getDecryptedFields();
client.decrypt(encryptedDoc, metadata).then((decryptedDoc) => {
    const plaintextFields = decryptedDoc.plaintextDocument;
$decryptedDocument = $client->decrypt($encryptedDoc, $metadata);
$plaintextFields = $decryptedDocument->getDecryptedFields();
The decrypt call is asynchronous and will resolve with the map of document id/name to decrypted bytes.