# Envoy Webhooks

Envoy is a workplace platform for visitor management, employee check-in and desk
booking. Envoy apps subscribe to events, and Envoy POSTs a JSON webhook to your
URL when a visitor signs in, an invite is created, and so on.

## When to Use This Skill

* How do I receive Envoy webhooks?
* How do I verify the `X-Envoy-Signature` header?
* Why is my Envoy webhook signature verification failing?
* How do I handle `entry_sign_in` or `invite_created` events?
* What does an Envoy webhook payload (`event` / `meta` / `payload`) look like?

## Verification (core)

`X-Envoy-Signature` = **base64** of HMAC-SHA256 over the **raw body**, keyed with
your Envoy **app's client secret**. No timestamp is part of the signed content.

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

function verifyEnvoySignature(rawBody, signature, secret) {
  if (!signature || !secret) return false;
  const expected = crypto.createHmac('sha256', secret)
    .update(rawBody)            // exact bytes received, not re-serialized JSON
    .digest('base64');          // base64, not hex
  const a = Buffer.from(signature, 'utf8');
  const b = Buffer.from(expected, 'utf8');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

// Express: read the raw body for any Content-Type
// app.post('/webhooks/envoy', express.raw({ type: '*/*' }), handler)

```

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

The official Node SDK (`@envoy/envoy-integrations-sdk`, `EnvoySignatureVerifier`)
does the same thing; the examples compute the HMAC directly so one approach works
in Node and Python.

## Setup

Envoy signs webhooks with your **Envoy app's client secret**; there is no separate
webhook secret. In the Envoy dashboard go to **Apps → Configure** on the Webhooks
card, pick events, enter your URL and click **Complete Setup**. Optional HTTP
Basic auth (`username:password`) can also be set on the endpoint; it is separate
from signature verification.

With Hookdeck, create an Envoy source and paste that client secret as the signing
secret. See [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/envoy-webhooks/references/setup.md).

## Common Event Types

The event name (topic) is the top-level `event` field; `payload` holds the entry
or invite and `meta` the location and company.

| Event | Triggered when |
| --- | --- |
| `entry_sign_in` / `entry_sign_out` | A visitor signs in / out |
| `entry_blacklist_review` | A visitor matched a blocklist rule and needs approval |
| `entry_blacklist_deny` | A visitor was denied entry by a blocklist rule |
| `entry_manually_updated` | An entry was edited in the visitor dashboard |
| `invite_created` / `invite_updated` / `invite_removed` | An invite was created / updated / deleted |
| `upcoming_visit` | There is an upcoming visit |
| `qr_code_sent` | The visitor received their invitee QR code email |
| `employee_entry_sign_in` / `employee_entry_sign_out` | An employee signs in / out |
| `employee_invite_created` / `employee_invite_updated` | An employee invite was created / updated |
| `employee_upcoming_visit` | One hour before an employee is due on-site |
| `employee_entry_blacklist_review` / `employee_entry_blacklist_deny` | Employee blocklist review / denial |
| `location_capacity_updated` | A location's capacity changed |
| `desk_sign_in` / `ticket_created` | Desk reserved / workplace issue created (beta) |

See [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/envoy-webhooks/references/overview.md) for payloads and retries.

## Environment Variables

```bash
# Your Envoy app's client secret
ENVOY_CLIENT_SECRET=your_envoy_app_client_secret

```

## Local Development

```bash
npx hookdeck-cli listen 3000 envoy --path /webhooks/envoy

```

No account required — the CLI creates a guest account on first run and gives
you a public HTTPS URL plus a web UI for inspecting requests. Use port `8000`
for the FastAPI example.

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/envoy-webhooks/references/overview.md) — Events, payload structure, retries
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/envoy-webhooks/references/setup.md) — Registering webhooks and finding the client secret
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/envoy-webhooks/references/verification.md) — Signature details, gotchas, debugging