# Webhooks

Mav can tell your systems when something happens to a contact, like a reply, a qualified lead, a call or an opt-out. Add a webhook to an agent, and Mav posts each event you pick to your URL as it happens.

In the Mav app, open the agent and click **Add lead box** under Outbound Notifications. Pick **Webhook**, enter your URL and choose the events. Leave every event unchecked to get them all.

## Payload

Each event is one `POST` with a JSON body. `activity` says what happened, and `contact` says who it happened to.

```json
{
  "activity": {
    "type": "outcome",
    "label": "qualified",
    "play_id": null,
    "next_engagement_id": "neg_3Fv8kQz1WpLc6R",
    "note": "Jordan Rivera qualified to talk to a rep.",
    "properties": {},
    "created_at": "2026-10-08T16:55:02Z",
    "updated_at": "2026-10-08T16:55:02Z"
  },
  "contact": {
    "id": "nct_7Hq2xKpR9vLm3N",
    "first_name": "Jordan",
    "last_name": "Rivera",
    "email": "jordan.rivera@example.com",
    "phone": "+13125550142",
    "opted_out": false,
    "created_at": "2026-10-06T16:42:18Z",
    "additional_info": {
      "current_carrier": "Example Mutual",
      "vehicles": "2"
    },
    "referral": {}
  }
}
```

## Fields

- `activity.type` (string, required): `event`, `outcome` or `conversion`.
- `activity.label` (string, required): Which event fired, like `qualified` or `opted_out`. See Events below.
- `activity.next_engagement_id` (string, required): The conversation the event belongs to. Every event in one conversation shares it.
- `activity.play_id` (null): Always `null` on the current Mav app.
- `activity.note` (string): A short summary of what happened, written for people.
- `activity.properties` (object): Extra details some events carry, like the conversion’s title on `custom_conversion`. Often empty.
- `activity.created_at` (ISO 8601 timestamp, required): When it happened.
- `activity.updated_at` (ISO 8601 timestamp, required): When Mav last changed it.
- `contact` (object, required): The contact, with the same fields Find a contact returns. Fields you sent that Mav doesn’t use land in `contact.additional_info` under their own names.

## Authentication

When you add the webhook, pick **Bearer** and enter a token. Mav sends it as a bearer token on every delivery, so your endpoint can check the request came from Mav.

```http
POST /your/webhook/path
Authorization: Bearer YOUR_WEBHOOK_TOKEN
Content-Type: application/json
```

## Testing

Once the webhook is saved, click **Send test** on it under Outbound Notifications. Mav posts one sample event to your URL right away, with your bearer token, and shows whether it went through or why it failed. Managers and admins see the button.

The sample uses a made-up contact named Test Contact. `activity.label` is the first event you picked, or `started` if you get them all, and `activity.properties.test` is `true` so your code can skip it. Nothing is saved to your account. That means `activity.next_engagement_id`, `activity.created_at`, `activity.updated_at` and `contact.created_at` are `null` in the sample. A failed test isn’t retried.

## Delivery

- **Reply fast.** Mav waits 3 seconds to connect and 3 more for your answer. Reply `200` first, then do the work.
- **Any 2xx counts.** Every other status is a failure. Mav doesn’t follow redirects, so a `3xx` fails too.
- **Failures retry.** Mav retries a failed delivery up to 18 times over about four days. If the last try fails, Mav turns the webhook off and emails your account’s admins and managers.
- **Expect repeats.** A retry can deliver an event twice, and payloads carry no event ID. Dedupe on `contact.id`, `activity.label` and `activity.created_at`.
- **Use HTTPS.** Payloads carry your contacts’ personal details.

## Events

Every event you can pick, grouped by `activity.type`.

- `event`: `started`, `interested`, `phone_call_scheduled`, `phone_call_started`, `phone_call_connected`, `phone_call_rep_attempted`, `phone_call_transferred`, `phone_call_transfer_failed`, `phone_call_completed`, `phone_call_missed`, `phone_call_received`
- `outcome`: `dormant`, `opted_out`, `filtered`, `undeliverable`, `qualified`, `not_interested`, `unqualified`
- `conversion`: `quoted`, `sold`, `link_clicked`, `custom_conversion`
