Skip to main content

Webhooks

Webhooks let Breezy notify your systems when service request and interaction events happen. Webhook endpoint management requires a user token. Service API keys cannot create, update, rotate, delete, or list webhook endpoints. Open the Webhooks tab in Breezy to manage endpoint configuration from the dashboard.

Supported events

Event typeWhen it fires
service_request.createdA new service request is created.
service_request.status_changedA service request status changes.
service_request.bookedA service request is booked through instant booking.
interaction.completedA voice or chat interaction is finalized.

Management flow

  1. Authenticate with a user JWT.
  2. POST /integrations/webhooks with a name, HTTPS URL, and event types.
  3. Store the returned signingSecret immediately. It is shown only once.
  4. Verify every delivery using the breezy-signature header.
  5. Rotate a signing secret when needed. Rotation immediately invalidates the old secret.
Local development URLs may use localhost, 127.0.0.1, or ::1. Production webhook URLs must use HTTPS.

Delivery format

Breezy sends POST requests with a JSON envelope:
{
  "id": "8d7f2a70-5b57-4c08-9e7d-8d6d52f517d2",
  "type": "service_request.created",
  "createdAt": "2026-06-17T18:00:00.000Z",
  "tenantId": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "serviceRequestId": "sr_...",
    "referenceNumber": "SR-1001",
    "channel": "web_chat",
    "serviceNeeded": "Water heater repair",
    "customer": {
      "name": "Ava Customer",
      "phoneNumber": "+15555550123",
      "emailAddress": "ava@example.com"
    }
  }
}
Deliveries include these headers:
HeaderDescription
breezy-event-idEvent id.
breezy-event-typeEvent type.
breezy-delivery-idStable delivery id for idempotency and support.
breezy-timestampISO 8601 timestamp used in signature verification.
breezy-signatureHMAC signature in v1=<hex> format.
Webhook payloads include operational fields needed by integrations, but do not include raw transcripts.

Event data

service_request.created data can include:
{
  "serviceRequestId": "sr_...",
  "referenceNumber": "SR-1001",
  "channel": "web_chat",
  "leadSourceId": "lead_source_...",
  "conversationId": "conv_...",
  "serviceNeeded": "Water heater repair",
  "preferredTimeWindow": "Tomorrow morning",
  "serviceAddress": "123 Main St, Denver, CO 80202",
  "serviceAddressLine1": "123 Main St",
  "serviceAddressLine2": "Unit 4",
  "serviceCity": "Denver",
  "serviceState": "CO",
  "serviceZipCode": "80202",
  "jobTypeFreetext": "Water heater",
  "jobClass": "plumbing",
  "jobTypeId": "job_type_...",
  "availabilityWindows": [],
  "customFields": {},
  "onlineBookingFormId": "booking_form_...",
  "customer": {
    "name": "Ava Customer",
    "firstName": "Ava",
    "lastName": "Customer",
    "phoneNumber": "+15555550123",
    "emailAddress": "ava@example.com"
  }
}
service_request.status_changed data:
{
  "serviceRequestId": "sr_...",
  "channel": "web_chat",
  "leadSourceId": "lead_source_...",
  "previousStatus": "new",
  "newStatus": "in_progress"
}
service_request.booked data:
{
  "serviceRequestId": "sr_...",
  "referenceNumber": "SR-1001",
  "interactionId": "voice_call_...",
  "confirmedWindowStart": "2026-06-18T16:00:00.000Z",
  "confirmedWindowEnd": "2026-06-18T18:00:00.000Z",
  "providerAppointmentId": "appt_..."
}
interaction.completed data:
{
  "interactionId": "interaction_...",
  "channel": "voice",
  "conversationOutcome": "booked"
}
Fields with no value are omitted from data.

Signature verification

Compute the expected signature with HMAC-SHA256:
signed_payload = breezy_timestamp + "." + raw_request_body
signature = "v1=" + hmac_sha256(signing_secret, signed_payload)
Compare your expected signature to breezy-signature using a constant-time comparison. Reject requests with missing headers, invalid signatures, or stale timestamps according to your integration’s tolerance.

Retries and history

Breezy treats any non-2xx response as a failed delivery. Failed deliveries are retried up to 3 total attempts, then marked abandoned. Deliveries are at least once. Use breezy-delivery-id as your idempotency key because a delivery can be retried after network or persistence uncertainty. Use GET /integrations/webhooks/deliveries to inspect recent delivery status. Pass endpointId to filter history for one endpoint.