> ## Documentation Index
> Fetch the complete documentation index at: https://docs.withsotto.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Subscribe to Sotto events and receive HTTP callbacks when they occur.

Webhooks let your systems react to events in Sotto in real time. You subscribe
to a **topic** by registering a callback **address**; when a matching event
occurs, Sotto sends an HTTP `POST` to that address.

Manage subscriptions with the [Webhooks endpoints](/api-reference/webhooks/list-webhooks)
(create, list, retrieve, and update).

## Topics

You can subscribe to the following topics:

| Topic            | Triggered when…                  | Payload       |
| ---------------- | -------------------------------- | ------------- |
| `user/opt-in`    | A user opts in to messaging.     | User object   |
| `user/opt-out`   | A user opts out of messaging.    | User object   |
| `user/update`    | A user's information is updated. | User object   |
| `ticket/updated` | A support ticket is updated.     | Ticket object |

<Note>
  A brand may register multiple webhooks, and the same address may subscribe to
  the same topic more than once. In non-development environments, callback
  addresses must use HTTPS.
</Note>

## Callback requests

Sotto delivers events as a `POST` to your registered address. Callbacks are
signed with the same HMAC scheme as API requests (see
[Authentication](/authentication)) and include these additional headers:

<ParamField header="x-bigco-api-version" type="string">
  The API version for the callback (e.g. `v1`).
</ParamField>

<ParamField header="x-bigco-webhook-id" type="string">
  The UUID of the webhook subscription that triggered this callback.
</ParamField>

<ParamField header="x-bigco-topic" type="string">
  The topic of the event (e.g. `user/opt-in`).
</ParamField>

### Payload

The body contains the time the event occurred and the associated resource:

```json theme={"dark"}
{
  "date_occurred": "2024-03-18T19:39:27Z",
  "data": {
    "id": 1,
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Doe",
    "email_address": "jane.doe@example.com",
    "messaging_consent": true,
    "date_created": "2024-03-04T23:02:32Z",
    "date_last_updated": "2024-10-04T23:02:32Z",
    "location": {
      "city": "New York",
      "county": "New York",
      "postal_code": "10001",
      "state": "New York",
      "state_code": "NY"
    },
    "custom_data": {
      "loyalty_tier": "Gold",
      "loyalty_points": 1000
    }
  }
}
```

For `user/*` topics, `data` is a [User](/api-reference/users/get-user-by-phone-number)
object.

### Responding

Your endpoint must return a `2xx` status code within **10 seconds**. Any other
response — or a timeout — is treated as a failure and the callback is retried
up to **20 times** before being dropped.

## Best practices

<AccordionGroup>
  <Accordion title="Make handlers idempotent" icon="rotate">
    Retries mean your endpoint may receive the same event more than once. Use
    `x-bigco-webhook-id` together with `date_occurred` to detect and safely
    ignore duplicates.
  </Accordion>

  <Accordion title="Verify every signature" icon="shield-check">
    Always validate the HMAC signature on incoming callbacks before acting on
    them, and serve your endpoint over HTTPS.
  </Accordion>

  <Accordion title="Acknowledge fast, process async" icon="bolt">
    Queue the event and return `200` immediately rather than doing heavy work
    inline. This keeps you within the 10-second window and avoids unnecessary
    retries.
  </Accordion>
</AccordionGroup>
