speakline

Webhook events

The events you choose reach the HTTPS address you set as a signed POST request.

Overview

Members with the owner or manager role add endpoints in the dashboard and choose which events each one receives.

  • 52 events in 8 groups.
  • Delivery is at least once: the same event can arrive more than once, so deduplicate on Speakline-Event-Id.
  • The address must use https; redirects are not followed.

Request

A delivery counts as successful when the endpoint answers 2xx within 5 seconds.

HeaderContent
Speakline-SignatureTimestamp and signature: t=…,v1=…
Speakline-Event-TypeThe event name
Speakline-Event-IdThe event id (UUID)
Speakline-Delivery-IdThe delivery id; it stays the same across retries
HTTP
POST /speakline-webhook HTTP/1.1
Content-Type: application/json
User-Agent: Speakline-Webhooks/1.0
Speakline-Event-Type: lead.created
Speakline-Event-Id: 0f6a2c4e-8b1d-4e3f-9a5c-7d2e1b0f4c6a
Speakline-Delivery-Id: 3c9d2b7e-41f0-4a8e-b6d5-9e2c7a1f0b84
Speakline-Signature: t=1793572520,v1=5f2c…

Event envelope

The body is a JSON envelope with the same fields for every event; event-specific fields sit in payload.

FieldContent
event_idThe event id
event_typeThe event name
schema_versionEnvelope version (currently 1)
company_idThe workspace id
occurred_atWhen the event happened (ISO 8601)
contextIds of the related records: call_id, lead_id, appointment_id …
payloadFields that depend on the event
JSON
{
  "event_id": "0f6a2c4e-8b1d-4e3f-9a5c-7d2e1b0f4c6a",
  "event_type": "lead.created",
  "schema_version": 1,
  "stream": "leads",
  "company_id": "7a3e5c1b-9d2f-4b8a-a6e4-c0f2d8b6a4e2",
  "occurred_at": "2026-10-23T14:02:11.482000+00:00",
  "context": { "lead_id": "5e1d9a3c-7b2f-4c8e-9a61-3f0b2d4c6e81" },
  "payload": {
    "id": "5e1d9a3c-7b2f-4c8e-9a61-3f0b2d4c6e81",
    "full_name": "Emma Clarke",
    "phone": "+442079460344",
    "email": "emma@example.com",
    "source": "inbound_voice",
    "status": "new",
    "language": "en",
    "created_at": "2026-10-23T14:02:11.482000+00:00"
  }
}

Verifying signatures

The Speakline-Signature header carries t (a Unix timestamp) and v1 (the signature). The signature is HMAC-SHA256 over t, a dot and the raw request body, keyed with the endpoint's secret and written as hex. Every attempt is signed again with a new timestamp.

  • Verify against the raw body, before parsing the JSON.
  • Compare in constant time.
  • We recommend rejecting requests older than 300 seconds.
  • The secret starts with whsec_ and is shown once, when it is created or rotated; rotating it invalidates the old one at once.
import crypto from "node:crypto";

// rawBody: the request body exactly as received (string or Buffer), before JSON.parse.
export function verifySpeaklineSignature(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")));
  const timestamp = Number(parts.t);
  if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest();
  const received = Buffer.from(parts.v1 ?? "", "hex");
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

Retries

Non-2xx responses, timeouts and connection errors count as failures, and the delivery is retried at the intervals below.

If all six attempts fail, the delivery is marked exhausted. The endpoint stays on, and the workspace's owners and managers are notified (at most once a day per endpoint). You can resend any delivery from its history in the dashboard.

AttemptAfter the previous attempt
1Immediately
21 minute
35 minutes
430 minutes
52 hours
66 hours

Event filter

Each endpoint selects its events with glob patterns. The default * means every event; an empty list sends none. Every pattern must match at least one event.

PatternEvents sent
*Every event
lead.*Lead events
callcenter.call_*Call events in the call center
appointment.bookedNew appointments only

Event catalogue

Call center

EventDescription
callcenter.call_queuedCall queued · A caller started waiting in a queue.
callcenter.call_offeredRinging an operator · A waiting call rang an operator.
callcenter.call_answeredOperator answered · An operator answered the call, with the time the caller waited.
callcenter.call_abandonedMissed call · The caller hung up while waiting in the queue.
callcenter.offer_declinedOperator declined · The operator declined the ringing call.
callcenter.offer_missedOperator missed · The ringing call went unanswered at the operator.
callcenter.call_overflowedMaximum wait reached · The queue's maximum wait ran out and the call went to the overflow target.
callcenter.callback_requestedCallback requested · The waiting caller asked to be called back instead of holding.
callcenter.callback_closedCallback closed · A callback was completed, missed or cancelled.
callcenter.call_heldCaller put on hold · The operator put the caller on hold.
callcenter.call_resumedBack from hold · The caller came back from hold.
callcenter.call_parkedCall parked · The operator parked the call.
callcenter.call_picked_upPicked up from park · An operator picked a parked call up.
callcenter.call_transferredCall transferred · The operator transferred the call to a person, a queue or a number.
callcenter.call_consultedConsultation · The operator consulted someone during the call.
callcenter.call_taken_overAssistant call taken over · A person took over a call the AI assistant was handling.
callcenter.call_completedCall completed · A call an operator handled ended, with talk and hold time.
callcenter.wrap_up_savedAfter-call form saved · The operator saved the result, note and tags.
callcenter.wrap_up_endedAfter-call work ended · The operator's after-call work ended.
callcenter.call_dialedOperator called out · An operator placed a call (click-to-call, callback, campaign).
callcenter.extension_dialedExtension dialed · A caller dialed an operator's extension in a call flow.
callcenter.internal_callOperator-to-operator call · An operator called a colleague.
callcenter.lead_skippedCampaign card skipped · An operator skipped a lead in an operator campaign.
callcenter.operator_status_changedOperator status changed · An operator became available, went on a break or went offline.

Calls

EventDescription
call.originatedOutbound call started · An outbound call was placed by the API, a campaign or an operator.
call.inbound_receivedInbound call received · An inbound call reached a number.
call.status_changedCall status changed · A call moved to a new status (ringing, in progress, completed, failed …).
call.transferredCall transferred to a number · The call was transferred to an outside number and answered (assistant, forward rule, call flow, queue overflow or operator).
call.insights_readyCall summary ready · The call's summary, sentiment and action items are ready.

Voicemails

EventDescription
voicemail.newVoicemail left · A caller left a voicemail.
voicemail.updatedVoicemail processed · A voicemail got its transcript or was matched to a lead.

Messaging

EventDescription
messaging.inbound_receivedInbound message received · A customer message arrived on a channel.
messaging.inbound_repliedAssistant replied · The AI assistant answered a customer message.
messaging.inbound_reply_skippedAssistant did not reply · The AI assistant did not answer (handed over, outside hours …).
messaging.outbound_sentOutbound message sent · A message was sent.
messaging.outbound_manual_sentMessage sent by hand · A person sent a message from the inbox.
messaging.outbound_sent_voice_toolMessage sent during a call · The voice assistant sent a message during a call.
messaging.outbound_failedMessage failed · A message could not be delivered.
nurture.outbound_sentFollow-up message sent · A follow-up (nurture) message was sent.

Leads

EventDescription
lead.createdLead created · A lead was created by hand, the API, a form, a call or a message. CSV imports do not send it.
lead.status_changedLead status changed · A lead's status changed (new → contacted → qualified …); the previous status comes too.

Campaigns

EventDescription
campaign.dispatchedCampaign call placed · A campaign called a lead.
campaign.text_sentCampaign message sent · A text campaign sent its message to a lead.
campaign.fallback_sentCampaign fallback message · A campaign sent its fallback message after an unanswered call.
campaign.lead_completedCampaign lead closed · A lead finished an operator campaign.

Appointments

EventDescription
appointment.bookedAppointment booked · An appointment was booked.
appointment.rescheduledAppointment rescheduled · An appointment moved to another time.
appointment.cancelledAppointment cancelled · An appointment was cancelled.
appointment.completedAppointment completed · An appointment was marked completed.
appointment.no_showAppointment no-show · The lead missed an appointment.
appointment.deletedAppointment deleted · An appointment was deleted.

Activity log

EventDescription
audit.loggedActivity record written · Every activity-log row (who changed what), for a SIEM.

On this page