deliveredAt is regenerated on each retry attempt; eventId is stable across retries — use it for idempotency.
voice_call.completed
Fires after a call ends and has been classified.transcript and recordingUrl are included only when enabled on the webhook configuration.
bookingOutcome—booked|declined|transferred|unknownagentHandledBy—chloe(AI) |human|unknownisEmergency— emergency classification from the AI or booking-window flagserviceTitanJobId/customerId— CRM linkage when a booking was made
lead.created
Fires when a new lead is recorded. Includes the raw inbound webhook body (when the lead arrived via webhook intake) underrawWebhook.
lead.booking_created
Fires when a booking is created for a lead — once per distinct CRM job. Multiple appointments booked in one conversation emit multiple events. For native-channel bookings (Google LSA, Yelp, web chat),campaign is null.
booking.bookedBy—ai|human|self_service|unknownbooking.crmJobIdcan benullwhen the event fires before the CRM job ID is recorded
lead.completed
Fires once per lead when it reaches the true end of its lifecycle — either its campaign finished, or it terminated at intake without ever entering a campaign.outcome—booked|unbooked|opted_out|failedbookingsCount— currently reports 0 or 1; derive exact counts fromlead.booking_createdeventserrorMessage— set only whenoutcomeisfailednotEnrolledReason— set only when the lead never entered a campaign
customer.communication_preference_changed
Fires when a customer opts out (STOP) or back in (START) of SMS. Currently SMS-only;email and voice channels are reserved for future use.