# Webhook events — v1 enrichment schema wazmeow's webhook payload is **fully backward compatible**. Every existing payload key (`type`, `event`, jid fields, etc.) is unchanged and every event type that was emitted before is still emitted. Spec 004 adds **one** new key to the webhook payload: **`v1`**. All v1 enrichment is nested under that single additive key. Consumers that don't know about `v1` simply ignore it. ```jsonc { "type": "CallOffer", // existing key — unchanged "event": { /* ... */ }, // existing key — unchanged // ... all other existing keys unchanged ... "v1": { // NEW — the only added key "schema_version": "1", "event": "v1.call.offer", "instance_id": "", "ts": "2026-05-17T22:00:00.123456789Z", "data": { /* event-specific fields */ } } } ``` ## Envelope | Field | Type | Notes | |------------------|--------|----------------------------------------------------| | `schema_version` | string | Always `"1"` for this schema. | | `event` | string | Dotted event name, e.g. `v1.call.offer`. | | `instance_id` | string | The wazmeow user/instance id. | | `ts` | string | RFC3339Nano UTC timestamp. | | `data` | object | Event-specific payload (see below). | ## Call events (`v1.call.*`) The `v1` object is co-emitted with the existing call webhook (`type` stays `CallOffer`/`CallAccept`/...). **All** call events keep `dowebhook=1` — none are suppressed, including `v1.call.relay_latency` and `v1.call.transport`. | Event | Emitted with `type` | Key `data` fields | |-------------------------|-----------------------|-----------------------------------------------------------------------------------| | `v1.call.offer` | `CallOffer` | `call_id`, `from`, `caller_phone`, `caller_lid`, `is_group`, `group_jid`, `media`, `platform`, `client_version`, `timestamp_unix_ms`, `raw_xml` | | `v1.call.offer_notice` | `CallOfferNotice` | `call_id`, `from`, `caller_phone`, `caller_lid`, `is_group`, `group_jid`, `media`, `notice_type`, `timestamp_unix_ms`, `raw_xml` | | `v1.call.accept` | `CallAccept` | `call_id`, `from`, `caller_phone`, `caller_lid`, `platform`, `client_version`, `timestamp_unix_ms` | | `v1.call.preaccept` | `CallPreAccept` | `call_id`, `from`, `caller_phone`, `caller_lid`, `platform`, `client_version`, `timestamp_unix_ms` | | `v1.call.transport` | `CallTransport` | `call_id`, `from`, `timestamp_unix_ms`, `raw_xml` | | `v1.call.terminate` | `CallTerminate` | `call_id`, `from`, `reason`, `terminated_by`, `timestamp_unix_ms`, **`duration_ms` (only when computable)** | | `v1.call.reject` | `CallReject` | `call_id`, `from`, `rejected_by`, `reject_type`, `timestamp_unix_ms` | | `v1.call.relay_latency` | `CallRelayLatency` | `call_id`, `from`, `timestamp_unix_ms`, `raw_xml` | | `v1.call.unknown` | `UnknownCallEvent` | `raw_xml`, `timestamp_unix_ms` | > **`duration_ms` is never fabricated.** Because there is no call-log table, > call duration is not computable from inbound webhook events alone, so > `v1.call.terminate.data.duration_ms` is **omitted** rather than guessed. > The sidecar hangup response (`/call/media/{call_id}/hangup`) does return a > measured `duration_ms` when a media bridge was active. ## Order events (`v1.order.*`) `v1.order.received` is the enrichment envelope for an inbound `OrderMessage`, built via `BuildOrderReceivedV1`. `data`: `message_id`, `business_jid`, `customer_jid`, `order_id`, `item_count`, `total`, `currency`, `products[]`, `enrichment_error`. ## Backward compatibility - No existing key is renamed or removed. - No event type stopped being emitted. - The only change to the payload is the addition of the single `v1` object. - A strict consumer that validates an exact key set should treat `v1` as an optional, ignorable field. ## See also - `docs/whatsapp-web-call-integration.md` — call-media (sidecar) integration. - `static/api/spec.yml` — full OpenAPI surface for the new endpoints.