> ## Documentation Index
> Fetch the complete documentation index at: https://docs.machines.cash/llms.txt
> Use this file to discover all available pages before exploring further.

# Encryption

> Encrypt card labels using server‑side helpers.

Machines cares about privacy—and this extends to API partners. We use end‑to‑end encryption for card UI metadata so only your users can read it. Use our helper endpoints so you don’t have to implement cryptography yourself.

What’s encrypted for cards:

* Card label (name) → <code>encryptedName</code>
* Color → <code>encryptedColor</code>
* Emoji → <code>encryptedEmoji</code>
* Memo/notes → <code>encryptedMemo</code>

<Note>Card secrets (PAN/CVC) are different. Use <code>POST /cards/secrets/session</code> + <code>POST /cards/{"{cardId}"}/secrets</code>. See <a href="/cards">Cards</a> → Secrets.</Note>

<Tip>Prerequisite: have a session token. See Authentication.</Tip>

## API flows (step‑by‑step)

<Steps>
  <Step title="Encrypt a card label (server-side)">
    <b>Endpoint</b>: <a href="/api/encryption/encrypt" target="_blank" rel="noreferrer"><code>POST /encryption/encrypt</code></a><br />
    <b>Body</b>: JSON with a <code>value</code> string (e.g., "Ops Card").<br />
    <b>Response</b>: returns an object with <code>value</code> (EncryptedField)

    ```bash theme={null}
    curl -s \
      -d '{"value":"Ops Card"}' \
      https://dev-api.machines.cash/partner/v1/encryption/encrypt
    ```
  </Step>

  <Step title="Decrypt a card label (server-side)">
    <b>Endpoint</b>: <a href="/api/encryption/decrypt" target="_blank" rel="noreferrer"><code>POST /encryption/decrypt</code></a><br />
    <b>Body</b>: JSON with a <code>value</code> EncryptedField.
    <b>Response</b>: plaintext card label in <code>value</code>

    ```bash theme={null}
    curl -s \
      -d '{"value":{"v":1,"iv":"Qz4f2m7Hk1P9x0ab","ct":"Hdbb2yT2F4xWZL5m5bJX3eJb4n8wVhjPzqLw2h7i"}}' \
      https://dev-api.machines.cash/partner/v1/encryption/decrypt
    ```
  </Step>
</Steps>

## Fields

<ParamField path="value" type="string" required>
  Plaintext to encrypt. For decryption, pass the encrypted object returned by <code>/encryption/encrypt</code>.
</ParamField>

## Response (encrypt)

<ResponseField name="value.v" type="number" required>
  Schema version.
</ResponseField>

<ResponseField name="value.iv" type="string" required>
  Base64url IV.
</ResponseField>

<ResponseField name="value.ct" type="string" required>
  Base64url ciphertext + auth tag.
</ResponseField>

## Card labels are optional

* You can omit <code>encryptedName</code> when creating a card and set it later with <code>PATCH /cards/{"{cardId}"}</code>.
* When you do set a card label, always use <code>/encryption/encrypt</code> and <code>/encryption/decrypt</code> (no manual cryptography needed).

## Default flow (server-side)

```mermaid theme={null}
sequenceDiagram
  participant Backend as Backend
  participant MachinesAPI as Machines API

  Backend->>MachinesAPI: POST /encryption/encrypt { value }
  MachinesAPI-->>Backend: { value: encryptedField }
  Backend->>MachinesAPI: POST /cards { encryptedName }
```

## Example (server-side)

```ts theme={null}
const labelRes = await fetch("https://dev-api.machines.cash/partner/v1/encryption/encrypt", {
  method: "POST",
  headers: { Authorization: `Bearer ${sessionToken}`, "Content-Type": "application/json" },
  body: JSON.stringify({ value: "Ops Card" }),
});
const { data: encrypted } = await labelRes.json();

await fetch("https://dev-api.machines.cash/partner/v1/cards", {
  method: "POST",
  headers: { Authorization: `Bearer ${sessionToken}`, "Content-Type": "application/json" },
  body: JSON.stringify({ encryptedName: encrypted.value }),
});
```

## Display card labels in your frontend (recommended)

1. List cards: <code>GET /cards</code>
2. Decrypt each <code>encryptedName</code> with <code>POST /encryption/decrypt</code>
3. Send plaintext labels to your frontend

```ts theme={null}
const cardsRes = await fetch("https://dev-api.machines.cash/partner/v1/cards", {
  headers: { Authorization: `Bearer ${sessionToken}` },
});
const { data: cardsData } = await cardsRes.json();

const labels = await Promise.all(
  cardsData.cards.map(async (card: { encryptedName: unknown; cardId: string }) => {
    const decryptRes = await fetch("https://dev-api.machines.cash/partner/v1/encryption/decrypt", {
      method: "POST",
      headers: { Authorization: `Bearer ${sessionToken}`, "Content-Type": "application/json" },
      body: JSON.stringify({ value: card.encryptedName }),
    });
    const { data } = await decryptRes.json();
    return { cardId: card.cardId, label: data.value };
  }),
);
```

<Note>Use <code>/encryption/decrypt</code> only for card labels and metadata. Card secrets (PAN/CVC) use <code>/cards/secrets/session</code> + <code>/cards/{"{cardId}"}/secrets</code>.</Note>

## Advanced (client-side, optional)

If you need client-side encryption, fetch a per-user data key via <code>GET /encryption/data-key</code> (requires <code>encryption.read</code>) and encrypt locally using AES-256-GCM.

### Encrypted field shape

```
{
  "v": 1,
  "iv": "<base64url>",
  "ct": "<base64url>"
}
```

* Canonical order is <code>v</code>, <code>iv</code>, <code>ct</code> (order doesn’t matter in JSON).
* <code>v</code>: schema version (currently 1)
* <code>iv</code>: 12-byte IV, base64url encoded
* <code>ct</code>: ciphertext + auth tag, base64url encoded

### Example (Node.js)

```ts theme={null}
import { createCipheriv, randomBytes } from "node:crypto";

function base64Url(buf: Buffer) {
  return buf.toString("base64").replace(/\\+/g, "-").replace(/\\//g, "_").replace(/=+$/g, "");
}

export function encryptField(plaintext: string, dataKeyBase64Url: string) {
  const key = Buffer.from(dataKeyBase64Url, "base64url");
  const iv = randomBytes(12);
  const cipher = createCipheriv("aes-256-gcm", key, iv);
  const ciphertext = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
  const tag = cipher.getAuthTag();
  const combined = Buffer.concat([ciphertext, tag]);
  return { v: 1, iv: base64Url(iv), ct: base64Url(combined) };
}
```

<Note>Card PAN/CVC secrets use a secrets session and AES-128-GCM. See <a href="/cards">Cards</a> for that flow.</Note>
