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

# Webhook Delivery

> Delivery envelope, headers, and signature verification for webhook events

Every delivery is an HTTP POST to your endpoint's URL with a JSON body in the following envelope:

```jsonc Delivery body theme={null}
{
  "id": "whn_741nn23lnunxy4r45ole9osh",
  "type": "account.updated",
  "created": "2026-07-10T06:16:48Z",
  "attempt": 1,
  "api_version": "2026-07",
  "account_id": "acct_a82j28co9hu6gnpg54xquxt5",
  "data": { /* the full business object — e.g. the account, same shape as Get Account */ }
}
```

<ResponseField name="id" type="string">
  Unique delivery-event id (`whn_…`). Retries reuse the same id — deduplicate on it.
</ResponseField>

<ResponseField name="type" type="string">
  The event type, e.g. `account.updated`. See the [event catalog](/va/webhooks/events).
</ResponseField>

<ResponseField name="created" type="datetime">
  When the event was created.
</ResponseField>

<ResponseField name="attempt" type="integer">
  1-based delivery attempt number.
</ResponseField>

<ResponseField name="api_version" type="string">
  API version of the payload shape. Currently `2026-07`.
</ResponseField>

<ResponseField name="account_id" type="string | null">
  Id of the related account (`acct_…`), or `null` for events without account context.
</ResponseField>

<ResponseField name="data" type="object">
  The event's business object, in the same shape as the corresponding GET endpoint.
</ResponseField>

## Headers

| Header                 | Value                                                          |
| ---------------------- | -------------------------------------------------------------- |
| `X-Webhook-Event-ID`   | Same as body `id`.                                             |
| `X-Webhook-Event-Type` | Same as body `type`.                                           |
| `X-Webhook-Timestamp`  | Unix timestamp (seconds) at send time; input to the signature. |
| `X-Webhook-Signature`  | Delivery signature — see below.                                |
| `X-Webhook-Attempt`    | Same as body `attempt`.                                        |

## Verifying the signature

Compute HMAC-SHA256 over the string `"{X-Webhook-Timestamp}."` + `raw_request_body` using your endpoint's signing secret (returned once at creation) as the UTF-8 key, then compare against the header value, which is formatted as `sha256=<hex digest>`. Always verify against the raw request bytes, before any JSON parsing or re-serialization.

```python Python theme={null}
import hashlib, hmac

def verify(secret: str, timestamp: str, raw_body: bytes, signature_header: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature_header)
```

<Note>
  Respond with any 2xx status within 10 seconds to acknowledge. Non-2xx responses and timeouts are retried with exponential backoff; retried deliveries carry the same `id` with an incremented `attempt`.
</Note>
