Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mortemlabs.com/llms.txt

Use this file to discover all available pages before exploring further.

Mortem supports optional AES-256-GCM encryption for event payloads. When you set a master key, the SDK encrypts every event payload before it is buffered and sent to the ingest service. The encrypted ciphertext is what Mortem stores — the plaintext never leaves your process unencrypted. Encryption is opt-in. If you do not set a master key, payloads are stored as plain JSON and the feature has no effect on the rest of the SDK.

Generate a master key

Use OpenSSL to generate a cryptographically random 256-bit key encoded as base64:
openssl rand -base64 32
Copy the output into your environment. Keep this value secret — treat it with the same care as your API key.

Set the environment variable

.env.local
MORTEM_MASTER_KEY=your_base64_encoded_32_byte_key_here
The SDK reads MORTEM_MASTER_KEY automatically when it is set in process.env. You do not need to pass the key anywhere in code for the SDK’s built-in instrumentation to encrypt payloads.
Keep the master key stable across deployments. If you rotate or lose the key, any previously encrypted payloads cannot be decrypted. There is no recovery path for payloads encrypted with a lost key.

How encryption works

When MORTEM_MASTER_KEY is present and valid, the SDK uses AES-256-GCM with a randomly generated 12-byte IV for every payload. The encrypted result is a structured object:
interface EncryptedPayload {
  algorithm: "aes-256-gcm"
  ivBase64: string       // base64-encoded 12-byte initialization vector
  tagBase64: string      // base64-encoded 16-byte GCM authentication tag
  ciphertextBase64: string  // base64-encoded encrypted JSON
}
Each payload gets a unique IV, so encrypting the same payload twice produces different ciphertext. The GCM authentication tag prevents silent ciphertext tampering.

Encrypt and decrypt manually

The SDK exports encryptPayload and decryptPayload for cases where you want to encrypt payloads yourself before passing them to beginEvent or eventBuilder.complete.

encryptPayload

import { encryptPayload } from "@mortemlabs/sdk"

const encrypted = encryptPayload(
  { step: "planning", result: "ready" },
  process.env.MORTEM_MASTER_KEY,  // optional — falls back to MORTEM_MASTER_KEY env var
)

if (encrypted !== undefined) {
  console.log(encrypted.algorithm)       // "aes-256-gcm"
  console.log(encrypted.ivBase64)        // base64 IV
  console.log(encrypted.ciphertextBase64) // base64 ciphertext
}
Returns undefined if the key is missing, invalid (not exactly 32 bytes after base64 decoding), or if encryption fails for any reason.

decryptPayload

import { decryptPayload } from "@mortemlabs/sdk"

const plaintext = decryptPayload(
  encrypted,
  process.env.MORTEM_MASTER_KEY,  // optional — falls back to MORTEM_MASTER_KEY env var
)

// plaintext is the original JsonValue, or undefined if decryption failed
Returns undefined if the key is wrong, the ciphertext has been tampered with (GCM tag mismatch), or if decryption fails for any other reason.

Function signatures

encryptPayload
(payload: JsonValue, masterKeyBase64?: string) => EncryptedPayload | undefined
Encrypts a JSON-serializable value. Pass the base64 master key explicitly, or omit it to use process.env.MORTEM_MASTER_KEY. Returns undefined on any failure.
decryptPayload
(encrypted: EncryptedPayload, masterKeyBase64?: string) => JsonValue | undefined
Decrypts an EncryptedPayload object. Pass the base64 master key explicitly, or omit it to use process.env.MORTEM_MASTER_KEY. Returns undefined on any failure.

Example: encrypt a custom event payload

import { Mortem, encryptPayload } from "@mortemlabs/sdk"

const mortem = new Mortem({
  apiKey: process.env.MORTEM_API_KEY ?? "",
  agentId: process.env.MORTEM_AGENT_ID,
})

const session = await mortem.startSession({
  inputSummary: "Execute private arbitrage strategy",
})

await session.run(async () => {
  const sensitivePayload = {
    strategy: "triangular-arb",
    targetProfit: 0.015,
    walletBalance: 42.5,
  }

  const encrypted = encryptPayload(sensitivePayload)

  const event = session.beginEvent("custom", encrypted ?? sensitivePayload)
  // ... do the work
  event.complete()
})
When MORTEM_MASTER_KEY is set and valid, the SDK automatically encrypts event payloads in the built-in instrumentation wrappers. You only need to call encryptPayload manually when constructing payloads yourself before passing them to beginEvent or complete.

Security checklist

  • Generate the key with openssl rand -base64 32 — do not use passwords or weak entropy sources.
  • Store the key in your secrets manager or deployment platform, not in committed files.
  • Never rotate the key without first backing up and decrypting all existing payloads you care about.
  • The key is exactly 32 bytes (256 bits) after base64 decoding. An incorrectly sized key causes encryptPayload to return undefined silently.