Encrypt Your Requests

Wrap request bodies in an AES-256-GCM envelope derived from your client secret key.

Field-level request encryption is optional and off unless you turn it on. While it is on, every request body must arrive as an encrypted envelope instead of plain JSON. Responses always come back as normal, unencrypted JSON.

GET and HEAD requests carry no body, so they are sent normally whether encryption is on or off.

If you have not enabled it, send request bodies as plain JSON exactly as the guides show, and skip this page.

Enabling encryption on your credential

Enable encryption from SettingsDeveloper API in Duplo Dashboard, the same menu you generate credentials from. You can switch it on or off whenever you like without rotating the key, because the client secret key is issued alongside the API key either way.

Encrypting a body needs that client secret key, which is shown once, at creation time. If you no longer have it, the only way to get a new one is to regenerate your credentials, which invalidates your current API key for that mode. Your encryption setting and IP allowlist carry over to the new key, and the other mode's key is untouched.

Turn it on in the right order

The setting takes effect immediately. Ship the encryption code first and enable the toggle once it is deployed, or in-flight plain JSON requests start failing with 400.

Building the encrypted envelope

  1. Derive a 32-byte AES-256 key as SHA-256(clientSecretKey).
  2. Encrypt your JSON request body with AES-256-GCM using a random 12-byte IV.
  3. Build the payload as iv (12 bytes) + ciphertext + authTag (16 bytes), base64-encoded.
  4. Send it as { "client": "<base64 payload>" }.

Generate a fresh IV for every request. The Authorization header and Content-Type: application/json are unchanged; only the body is wrapped.

The samples below use a placeholder endpoint and payload, because the Duplo Dashboard endpoints documented today are read-only GETs that carry no body. Substitute the body-bearing endpoint your integration calls.

const crypto = require("crypto");
const axios = require("axios");

const encryptBody = (body, clientSecretKey) => {
  const key = crypto.createHash("sha256").update(clientSecretKey).digest();
  const iv = crypto.randomBytes(12);
  const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);

  const ciphertext = Buffer.concat([
    cipher.update(JSON.stringify(body), "utf8"),
    cipher.final(),
  ]);

  const payload = Buffer.concat([iv, ciphertext, cipher.getAuthTag()]);

  return { client: payload.toString("base64") };
};

const sendEncryptedRequest = async () => {
  const response = await axios.post(
    "https://dashboard.tryduplo.com/api/<endpoint>",
    encryptBody({ field: "value" }, "<your-client-secret-key>"),
    {
      headers: {
        Authorization: "Bearer <your-api-key>",
        "Content-Type": "application/json",
      },
    },
  );

  console.log(response.data);
};

sendEncryptedRequest();

Handling encryption errors

If encryption is enabled on your key but the envelope is missing or fails to decrypt, you get a 400 with one of two messages:

MessageWhat it means
Encrypted request body is requiredEncryption is on, but the body had no client field, or it was empty.
Unable to decrypt request bodyThe envelope did not decrypt: it is malformed, truncated, or encrypted with the wrong key.
Decrypted request body is invalidThe envelope decrypted, but the plaintext inside was not a JSON object.
Encryption is misconfigured for this keyEncryption is on for your credential but the key material behind it cannot be used. Regenerate your credentials, or contact support if it persists.

The reverse mistake has its own message. Sending a { "client": ... } envelope to a key that does not have encryption enabled returns 400 with This request includes a client field, but encryption is not enabled for this API key. Send the plain (unencrypted) request body instead. If you see that, the envelope is fine and the toggle is off.

Because responses stay unencrypted, you can read the error straight off the wire while you are getting the envelope right.

How is this guide?

Last updated on

On this page