# Emporix Webhooks

Emporix (composable commerce platform) delivers webhooks through Svix.
This skill covers the two Svix strategies: **Svix-Shared** (the default) and a **Licensed account - Svix**
(your own Svix account). Each delivery is an HTTP `POST` with a JSON body and three signature headers:
`svix-id`, `svix-timestamp`, and `svix-signature`.

**Not covered:** the **Other - HTTP** strategy (`emporix-event-signature` header, base64 HMAC over
alphabetically re-sorted JSON). Hookdeck's Emporix source only supports the Svix strategies.

## When to Use This Skill

* How do I receive Emporix webhooks?
* How do I verify Emporix webhook signatures (`svix-signature`)?
* How do I handle `order.created`, `customer.created` or `product.updated` events?
* Where do I find the Emporix webhook signing secret (`whsec_...`)?
* Why is my Emporix webhook signature verification failing, or failing on retries?

## Verification (core)

Signed content is `{svix-id}.{svix-timestamp}.{raw body}`. Svix signs it with HMAC-SHA256 using the
base64-decoded endpoint secret (the part after `whsec_`), base64-encodes the digest, and sends one or
more space-delimited `v1,<signature>` entries (several during secret rotation). The secret comes from
the Svix dashboard (**Administration > Webhooks > Open Svix Dashboard > Endpoints**); Emporix's own pages
never show it, so the `whsec_` format is Svix's, not Emporix's.

```javascript
import { Webhook } from 'svix'; // svix 2.x is ESM-only

const wh = new Webhook(process.env.EMPORIX_WEBHOOK_SECRET); // "whsec_..."
// rawBody: the raw Buffer/string, never re-serialized JSON
wh.verify(rawBody, {
  'svix-id': req.headers['svix-id'],
  'svix-timestamp': req.headers['svix-timestamp'],
  'svix-signature': req.headers['svix-signature'],
}); // throws WebhookVerificationError on a bad signature or stale timestamp
const body = JSON.parse(rawBody.toString('utf8')); // parse only after verify passes

```

```python
from svix.webhooks import Webhook, WebhookVerificationError

wh = Webhook(os.environ["EMPORIX_WEBHOOK_SECRET"])
wh.verify(raw_body, {"svix-id": msg_id, "svix-timestamp": ts, "svix-signature": sig})

```

The `standardwebhooks` library also works if you pass the `svix-*` values as `webhook-id`,
`webhook-timestamp` and `webhook-signature`.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/emporix-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/emporix-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/emporix-webhooks/examples/fastapi/).
> Express reads the body with `express.raw({ type: '*/*' })` so any content type verifies.

### Retries and replays through Hookdeck

The `svix` and `standardwebhooks` libraries always enforce a fixed 5-minute timestamp window. Hookdeck
retries and replays resend the original `svix-timestamp`, so the library rejects any retry that lands
more than 5 minutes after the original delivery. If your endpoint sits behind Hookdeck (or you replay
events), use the manual verifier in [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/emporix-webhooks/references/verification.md), where the
window can be dropped or widened.

## Common Event Types

Event types are dotted strings. Emporix documents each event's **payload** schema but no envelope, and
Svix sends no event-type header, so the examples read `eventType` from the body if present and otherwise
from an `?eventType=` query parameter on the endpoint URL (an example convention: register one Svix
endpoint per event type).

| Event | Triggered When |
| --- | --- |
| `order.created` | An order is created |
| `order.updated` | An order is updated |
| `customer.created` | A customer is created |
| `product.created` | A product is created |
| `product.updated` | A product is updated |

See [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/emporix-webhooks/references/overview.md) for the full event list by service.

## Environment Variables

```bash
# Svix dashboard > Endpoints > your endpoint > Signing Secret (starts with whsec_)
EMPORIX_WEBHOOK_SECRET=whsec_xxxxx

```

## Local Development

```bash
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 emporix --path /webhooks/emporix

```

Add the tunnel URL as an endpoint in the Svix dashboard (**Administration > Webhooks > Open Svix Dashboard >
Endpoints > Add endpoint**), then subscribe to events under **Administration > Webhooks**.

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/emporix-webhooks/references/overview.md) - Strategies, full event list, payload notes, limits
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/emporix-webhooks/references/setup.md) - Choose a strategy, add an endpoint, get the signing secret
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/emporix-webhooks/references/verification.md) - Signature details, manual verifier, timestamp window, gotchas