Skip to main content
The cNGN API encrypts payloads in both directions:
  • Requests (POST/PUT bodies): you encrypt the JSON payload with AES-256-CBC using the encryption key from your dashboard.
  • Responses: the API encrypts the data field of every successful response to your Ed25519 public key. You decrypt it locally with your private key.
The official SDKs implement both sides of this automatically. Read on only if you’re integrating directly over HTTP.

Encrypting requests (AES-256-CBC)

Every endpoint that accepts a body expects this wire format instead of the plain JSON:
Steps:
  1. SHA-256 hash your encryption key to derive a 32-byte AES key.
  2. Generate a random 16-byte initialization vector (IV); use a fresh one per request.
  3. Encrypt the JSON string with AES-256-CBC.
  4. Base64-encode the ciphertext and the IV, and send them as content and iv.
The official AESCrypto implementations (the decrypt method is included for local round-trip testing):
Usage: AESCrypto.encrypt(JSON.stringify(payload), encryptionKey) returns the {content, iv} object to send as the request body.
Sending a plain JSON body to a POST/PUT endpoint fails with 400 Missing encryption data, key, or IV. A body that can’t be decrypted fails with 400 Decryption failed.

Decrypting responses (Ed25519 / Curve25519)

Successful responses return an encrypted base64 string in data:
The payload is encrypted with libsodium’s crypto_box to your Ed25519 public key (converted to Curve25519). The base64-decoded blob is laid out as: The official Ed25519Crypto implementations take your OpenSSH-format private key (the cngn_api_key file) directly; they locate the 64-byte key data after the 0x00 0x00 0x00 0x40 length marker, convert it to Curve25519, and open the box:
Usage: Ed25519Crypto.decryptWithPrivateKey(privateKeyFileContents, response.data) returns the decrypted JSON string; parse it to get the payload.

Key management summary