# Hume Webhooks

Webhooks from **Hume AI** (hume.ai), the emotionally intelligent voice AI company. This skill covers **EVI (speech-to-speech) webhooks only**, which are configured on an EVI Config and report the lifecycle of EVI Chat sessions.

## Setup Note

For Hume EVI (speech-to-speech) webhooks. Paste the webhook signing key from the Developers page.

## When to Use This Skill

* How do I receive Hume EVI webhooks?
* How do I verify the `X-Hume-AI-Webhook-Signature` header?
* Why is my Hume webhook signature verification failing?
* How do I handle `chat_started`, `chat_ended` and `tool_call` events?
* How do I subscribe an EVI Config to webhook events?

## Verification (core)

Hume signs each request with two headers:

```http
X-Hume-AI-Webhook-Signature: <hex digest>
X-Hume-AI-Webhook-Timestamp: <unix epoch seconds>

```

The digest is `HMAC-SHA256(signing key, "<raw body>.<timestamp>")`, lowercase hex, sent bare with **no prefix**. Note the order: **body first, then a period, then the timestamp**. The key is the signing key's UTF-8 bytes, used as-is. Build the signed message as **bytes**: the raw body, a literal `.`, then the timestamp header exactly as received. Never decode and re-encode the body, and never `JSON.parse` / `JSON.stringify` before verifying.

```javascript
const crypto = require('crypto');

function verifyHumeSignature(rawBody /* Buffer */, signatureHeader, timestampHeader, secret) {
  if (!secret || !signatureHeader || !timestampHeader) return false;

  // The whole header is one hex digest; validate format BEFORE decoding
  if (!/^[0-9a-fA-F]{64}$/.test(signatureHeader)) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(Buffer.concat([rawBody, Buffer.from('.'), Buffer.from(timestampHeader, 'latin1')]))
    .digest();
  const provided = Buffer.from(signatureHeader.toLowerCase(), 'hex'); // hex is case-insensitive
  return provided.length === expected.length && crypto.timingSafeEqual(provided, expected);
}

```

Missing or empty signature or timestamp header, malformed value, or mismatch: respond **401**.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/hume-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/hume-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/hume-webhooks/examples/fastapi/).

Hume's docs show manual verification code and no verification helper in an SDK, so the examples implement the documented algorithm directly. The signing key is the account's **webhook signing key**: Hume platform → **Developers** page → **Generate signing key**.

### Timestamp tolerance is opt-in

Hume's own example rejects deliveries more than 180 seconds old. This skill does **not** by default: Hookdeck retries and replays resend the original headers and timestamp, and Hookdeck applies no tolerance itself, so a fixed window would reject legitimate retries. Set `HUME_WEBHOOK_TOLERANCE_SECONDS` to opt in (`X-Hume-AI-Webhook-Timestamp` is Unix seconds; unset or `0` = off). Because the timestamp is signed, it cannot be swapped for a fresh one.

## Event Types

Dispatch on the body's `event_name` field.

| `event_name` | Triggered When | Key fields |
| --- | --- | --- |
| `chat_started` | A Chat session starts (new or resumed) | `chat_id`, `chat_group_id`, `config_id`, `start_time` (ms), `chat_start_type` (`new_chat_group` or `resumed_chat_group`) |
| `chat_ended` | A Chat session ends | `end_time` (ms), `duration_seconds`, `end_reason` (e.g. `USER_ENDED`, `USER_TIMEOUT`, `MAX_DURATION_TIMEOUT`, `INACTIVITY_TIMEOUT`, `ERROR`) |
| `tool_call` | The model calls a tool during a Chat | `timestamp` (ms), `tool_call_message` with `name`, `parameters` (stringified JSON), `response_required`, `tool_call_id`, `tool_type` (`builtin` or `function`) |

Every payload also carries `chat_group_id`, `chat_id`, `config_id`, and optional `caller_number` (E.164, Twilio phone calls only) and `custom_session_id` (custom language models only). Timestamps inside payloads are **milliseconds**; the header timestamp is **seconds**.

Log and acknowledge any other `event_name` rather than failing.

## Important Details

* **Method:** `POST`. Hookdeck's Hume source manages the method as POST.
* **Subscribing:** add a `webhooks` entry to an EVI Config: `{ "url": "...", "events": ["chat_started", "chat_ended", "tool_call"] }`. Only subscribed events are sent.
* **Rotating the key:** generating a new signing key immediately invalidates the old one. Only admins can do it in an organization.
* **`tool_call` replies:** if `response_required` is true, send the tool response (or a tool error) back to EVI through the Control Plane API; the webhook response body is not used for it.
* **Retries:** Hume's webhook docs do not describe a retry or timeout policy. Respond quickly and process asynchronously.
* **No delivery ID header.** Build an idempotency key yourself, e.g. `chat_id` + `event_name` (+ `tool_call_id` for tool calls).

## Environment Variables

```bash
HUME_WEBHOOK_SECRET=your_webhook_signing_key   # Developers page > Generate signing key
HUME_WEBHOOK_TOLERANCE_SECONDS=0               # optional; unset or 0 = no timestamp window (default)

```

Hume's docs call the variable `HUME_WEBHOOK_SIGNING_KEY`; this skill uses `HUME_WEBHOOK_SECRET` throughout.

## Local Development

```bash
# Forward Hume webhooks to your local server (no account required)
npx hookdeck-cli listen 3000 hume --path /webhooks/hume

```

Put the resulting HTTPS URL in the `webhooks` array of your EVI Config, then start a Chat that uses that Config.

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/hume-webhooks/references/overview.md) - Hume EVI webhook concepts, events, payload fields
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/hume-webhooks/references/setup.md) - Generate the signing key and subscribe an EVI Config
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/hume-webhooks/references/verification.md) - `X-Hume-AI-Webhook-Signature` verification details and gotchas