# Agntix Webhooks

Agntix ([agntix.ai](https://agntix.ai)) is a voice and chat AI-agent platform. It sends an HTTPS
`POST` with a signed JSON body when a session starts and when it ends (the latter with the
post-call analysis). Delivery is by Svix, which follows
Standard Webhooks and signs with the `svix-*` header names:
`svix-id`, `svix-timestamp` and `svix-signature`.

The body is a **flat** envelope (no `data` wrapper):
`{ "id": "<session UUID>", "eventType": "session.ended", "type": "VOICE", "platform": "PHONE", "direction": "OUTBOUND", "state": "CLOSED", "agentId": "...", "createdAt": "...", "metadata": { "sessionVariables": { ... } } }`.
The event name is the top-level `eventType`. The top-level `type` is the session kind (`VOICE` or
`CHAT`), **not** the event name. `id` is the session UUID, which Agntix tells you to use as the
idempotency key. `session.ended` adds `lastActivityAt`, `endedAt`, `analysis` and `recordingUrl`.

## When to Use This Skill

* How do I receive Agntix webhooks?
* How do I verify Agntix webhook signatures (`svix-signature`)?
* How do I handle `session.created` and `session.ended` events and the post-call `analysis`?
* How do I get the Agntix signing secret (Developer > Add Endpoint)?
* Why is my Agntix webhook signature verification failing, or rejecting Hookdeck retries?

## Verification (core)

Signed content is `{svix-id}.{svix-timestamp}.{raw body}`. Svix signs it with HMAC-SHA256 using
the base64-decoded secret (the part after `whsec_`), base64-encodes the result, and sends one or
more space-separated `v1,<signature>` entries. Use the official `svix` library, which compares in
constant time. Read the `svix-*` headers, and when `svix-id` is absent fall back to the `webhook-*`
headers (`webhook-id`, `webhook-timestamp`, `webhook-signature`), as Hookdeck does.

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

const prefix = req.headers['svix-id'] ? 'svix' : 'webhook';
const id = req.headers[`${prefix}-id`];
const timestamp = req.headers[`${prefix}-timestamp`];
const signature = req.headers[`${prefix}-signature`];
// rawBody: the raw Buffer/string, never re-serialized JSON
new Webhook(process.env.AGNTIX_WEBHOOK_SECRET).verify(rawBody, {
  'svix-id': id, 'svix-timestamp': timestamp, 'svix-signature': signature,
  'webhook-id': id, 'webhook-timestamp': timestamp, 'webhook-signature': signature,
}); // throws on a bad signature or a timestamp outside the window
const event = JSON.parse(rawBody.toString('utf8')); // parse only after verify passes

```

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

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

```

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

Each endpoint has its own signing secret, shown for the endpoint in the dashboard's **Developer**
section (Svix). Agntix doesn't print the secret's form, but Svix secrets start with `whsec_`. Keep
the full value in `AGNTIX_WEBHOOK_SECRET`. Handlers fail closed: with the variable unset (or not a
`whsec_` value) they return 500 instead of accepting anything. A missing header or bad signature
gets a 400.

Read the raw body: Agntix's docs say to verify on "the **raw request body**, not a parsed JSON
object". With Express use `express.raw({ type: '*/*' })` so any content type works and the
exact bytes are verified.

### Hookdeck retries and replays hit the 5-minute window

The `svix` library always enforces a fixed 5-minute timestamp window, and it can't be configured.
Hookdeck retries and replays resend the **original** `svix-timestamp`, so the library rejects any
retry or replay that happens more than 5 minutes after the original delivery. If you verify
behind Hookdeck (or replay old events), use the manual verifier in
[references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/agntix-webhooks/references/verification.md), where the window can be dropped or
widened. Deduplicate on the envelope `id` instead of relying on the timestamp.

## Common Event Types

Two events are delivered today (the list may not be exhaustive). The name is `eventType` in the
JSON body, and the examples handle both:

| Event | Triggered When |
| --- | --- |
| `session.created` | A session is initiated (for outbound calls, before pickup) |
| `session.ended` | A session closes (hangup, timeout, TTL or manual), with `analysis` and `recordingUrl` |

`session.updated` and `knowledge_store.updated` are documented as planned: they exist only as
in-app SSE signals and are **not** delivered as webhooks. Return `2xx` for any event you don't
handle.

Delivery is at least once and expects a `2xx` within 15 seconds; failures retry with exponential
backoff for up to 24 hours. Both events carry the same session `id`, so deduplicate on `id` plus
`eventType`, return `2xx`, then process asynchronously. The webhook is summary-grade: fetch the
full transcript from the API when you need it. See [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/agntix-webhooks/references/overview.md).

## Environment Variables

```bash
# Signing secret of the webhook endpoint (Svix format, starts with whsec_)
AGNTIX_WEBHOOK_SECRET=whsec_xxxxx

```

## Local Development

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

```

Add the tunnel URL under **Developer > + Add Endpoint** (see
[references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/agntix-webhooks/references/setup.md)), subscribe to `session.created` and `session.ended`,
then place a test call or chat session.

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/agntix-webhooks/references/overview.md) - Agntix webhook concepts, events, payload shapes, delivery
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/agntix-webhooks/references/setup.md) - Add an endpoint, get the secret, choose events
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/agntix-webhooks/references/verification.md) - Svix verification details, header fallback, manual verifier, timestamp window