
# Crypto & Digest

Two small families that solve two unrelated problems: proving a payload was not tampered with, and turning a flood of events into one message a human will actually read.

## Crypto — Hashing & HMAC

Two operators, computing digests and signatures — typically to verify an inbound webhook or sign an outbound one.

| Operator | Props                                       | Description                                             |
| -------- | ------------------------------------------- | ------------------------------------------------------- |
| `hash`   | `input`, `algorithm`, `encoding?`           | Hash with `md5` / `sha256` / `sha512`.                  |
| `hmac`   | `input`, `secret`, `algorithm`, `encoding?` | Keyed HMAC with `sha256` / `sha512`, keyed by `secret`. |

`algorithm` is **required** on both. `encoding` is `hex` (the default) or `base64` on both.

```yaml
- name: signPayload
  type: crypto
  operator: hmac
  props:
    input: '{{trigger.data.body}}'
    secret: $env.SIGNING_SECRET
    algorithm: sha256
    encoding: hex
```

:::callout
**`hmac` does not accept `md5`.** Its algorithm enum is `sha256` and `sha512` only, while `hash` still accepts `md5` for interoperating with legacy systems. Never reach for `md5` on a signature you are relying on.
:::

Keep the key in the environment (`$env.SIGNING_SECRET`), never inline in the config — the config is code, and it ships to a git remote.

## Digest — Batch & Release

Two operators that collect items across many runs into a named bucket, then drain them as one batch. The classic use is a notification roll-up: one automation collects each event as it happens, a second releases them on a schedule.

| Operator  | Props                                 | Description                                                              |
| --------- | ------------------------------------- | ------------------------------------------------------------------------ |
| `collect` | `digestKey`, `item`, `deduplicateBy?` | Add an item to a named bucket, optionally deduplicating.                 |
| `release` | `digestKey`, `sort?`, `limit?`        | Drain a bucket — optionally sorted (`{ field, direction? }`) and capped. |

`digestKey` is **required** on both operators and is what pairs a producer with its consumer. `sort.direction` is `asc` by default.

```yaml
# Producer automation (record trigger) collects
- name: queueDigest
  type: digest
  operator: collect
  props:
    digestKey: daily-summary
    item: '{{trigger.data.record}}'
    deduplicateBy: id

# Consumer automation (cron trigger) releases
- name: drain
  type: digest
  operator: release
  props:
    digestKey: daily-summary
    sort: { field: created_at, direction: desc }
    limit: 50
```

:::callout
**The prop is `digestKey`, not `bucket`.** A digest action written with `bucket:` fails at runtime with `digest.collect requires a digestKey`. The name is unrelated to storage [buckets](/en/docs/buckets-overview), which hold files.
:::

Two runs, not one: `collect` belongs in an automation triggered by the event (a [record trigger](/en/docs/trigger-record-comment)), and `release` in one triggered by the clock (a [cron trigger](/en/docs/trigger-webhook-cron)). Because `release` drains, a released bucket starts empty for the next window — a missed schedule accumulates rather than losing events.

## Related Pages

- [Data & State](/en/docs/automation-data-actions) — the `data`, `state` and `filter` families.
- [Webhook & Cron Triggers](/en/docs/trigger-webhook-cron) — the inbound signature `hmac` verifies, and the schedule that drives `release`.
- [Email Actions](/en/docs/automation-email-actions) — sending the batch a digest releases.
- [HTTP & Webhooks](/en/docs/automation-http-actions) — signing an outbound request.
- [Environment Variables](/en/docs/env-vars) — where `$env.SIGNING_SECRET` comes from.
