Skip to content
Docs

Type to search. Arrow keys to move, Enter to open, Escape to close.

Developers

Outgoing webhooks

SIGNL can call a URL of yours when something happens: a call is booked, a payment lands, a form is submitted. Use it to feed your own systems, Zapier, Make or n8n.

53 events

Set one up

Where

Agency settings

Agency settings, Outgoing webhooks. Add the URL, choose the events (or all of them with *), and optionally set a signing secret. An organisation can have up to 100 active endpoints.

Zapier

instant triggers

The SIGNL Zapier app's instant triggers (New Booking, Call Won, New Form Submission, Payment Received, Deal Stage Changed) create their own endpoints, named Zapier: … and limited to that Zap's client. Leave them alone: switching the Zap off removes its endpoint.

Formats

signl · discord

The default format posts the JSON below. A Discord endpoint receives a ready-made embed instead and is not signed, because Discord does not verify a signature.

Who sees what

every client, or one

By default an endpoint receives the events of every client you run, and each payload names its client in data.clientId. Limit an endpoint to one client when its receiver should not see the others' leads and payments; it then gets only that client's events, and none that name no client.

What arrives

Request

POST, JSON

One POST per event per endpoint, with Content-Type: application/json and this envelope. id is the delivery id (the same value as the X-SIGNL-Delivery header, and the same on every retry of it), and data is the event's own fields.
{
  "id": "9b1f0c2e-…",
  "event": "call.booked",
  "data": { "clientId": "…", "leadId": "…", "scheduledAt": "2026-10-01T14:00:00Z" },
  "timestamp": "2026-09-30T09:12:44.120Z"
}

Signature

signed by default

A new endpoint gets a generated secret, shown once when you create it (you can also choose your own, and rotate it later). The request carries X-SIGNL-Signature: sha256=<hex>, an HMAC-SHA256 of the raw body keyed with the secret. An endpoint created before this without a secret stays unsigned until you rotate one in; a Discord endpoint is never signed.

Headers

on signed endpoints

X-SIGNL-Event (the event name), X-SIGNL-Timestamp (the envelope's own timestamp, to reject a replayed request), X-SIGNL-Delivery (the delivery id, the same on every retry) and Idempotency-Key (the same value, under the name most receivers already de-duplicate on). A replay from the log carries its own delivery id.
import { createHmac, timingSafeEqual } from 'node:crypto'

// rawBody is the exact request body, before any JSON parsing; secret is the one you set on the endpoint.
const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex')
const given = req.headers['x-signl-signature'] ?? ''
const ok = given.length === expected.length && timingSafeEqual(Buffer.from(given), Buffer.from(expected))

Delivery

retried on failure

Each attempt is logged with the status your endpoint returned. A timeout, a dropped connection, a 5xx, 408, 425 or 429 is retried up to four more times, after 1, 5, 30 and 120 minutes, always with the same X-SIGNL-Delivery id, so you can tell you have already seen it. Any other 4xx is not retried, and a 410 pauses the endpoint. After the last attempt the delivery stays in the log, marked failed, in Agency settings, Webhooks, where you can replay it by hand. Answer quickly with a 2xx and do the work afterwards.

Send test

from the endpoint

Send test, on an endpoint in Agency settings, sends that endpoint the latest real event it was sent, again. It is signed like any delivery and carries its own delivery id, so a receiver that de-duplicates on the id will accept it. An endpoint that has not been sent anything yet has nothing to test with.

Not live

workspaces

A workspace that is paused or being closed announces nothing, so a receiver sees no events for it.

Events

53 across 16 areas. Under each, the fields of data: a field marked ? is sent by some sources only, and an event marked open may carry further scalar fields its source attaches. Times are ISO 8601; money is whole minor units (pence, cents).

visitor

visitor.identified

A visitor became a known lead (an email was captured). clientId: string · visitorId: string · email: string

call

call.booked

A call was booked: through a booking page, Calendly, or entered by hand. clientId: string · callId?: string · visitorId?: string · bookingPageId?: string · bookingPageName?: string · scheduledAt: string · source?: string · inviteeEmail?: string · inviteeName?: string · eventName?: string · leadName?: string · callType?: string · dealValuePence?: number

call.cancelled

A booked call was cancelled. clientId: string · callId?: string · bookingPageId?: string|null · scheduledAt: string|null · visitorId?: string · source?: string · inviteeEmail?: string · cancelReason?: string|null

call.rescheduled

A booked call moved to a new time. clientId: string · callId?: string · bookingPageId?: string|null · previousScheduledAt: string|null · scheduledAt: string|null · visitorId?: string · source?: string · inviteeEmail?: string

call.showed

The lead attended the call. clientId: string · callId: string · status: string

call.no_show

The lead did not attend the call. clientId: string · callId?: string · bookingPageId?: string|null · scheduledAt: string|null · visitorId?: string · source?: string · inviteeEmail?: string

call.won

A call was marked won. clientId: string · callId: string · outcome: string

call.lost

A call was marked lost. clientId: string · callId: string · outcome: string · objection?: string

call.confirmed

open payload

The lead (or the rep) confirmed the call. clientId: string · visitorId?: string · call_id: string · scheduled_at: string · booking_page_id?: string|null · lead_email?: string|null · confirmed_by_talent_id?: string|null

call.reconfirmation_lapsed

open payload

A call was not reconfirmed in time. clientId: string · visitorId?: string · call_id: string · scheduled_at: string · booking_page_id?: string|null · lead_email?: string|null

call.inbound_dni

open payload

A call came in on a tracking number. clientId: string · visitorId?: string · from?: string · to?: string

call.scored

A call was scored against a scorecard (or rescored). Fires once per scoring run. clientId: string · callId: string · callScoreId: string · rubricId: string · overallScore: number · requiredMisses: number · needsReview: boolean · reviewThreshold: number · scoredAt: string

call.score_below_threshold

A scored call needs review: its score is under the scorecard's review threshold, or it missed a required criterion. Sent with call.scored, never instead of it. A flag for a person, never an action on the lead. clientId: string · callId: string · callScoreId: string · rubricId: string · overallScore: number · requiredMisses: number · needsReview: boolean · reviewThreshold: number · scoredAt: string

deal

deal.created

A deal was created. clientId: string · dealId: string · leadName: string · valuePence: number

deal.won

A deal was closed won. clientId: string · dealId: string · status: string · contractId?: string

deal.stage_changed

open payload

A deal moved to another pipeline stage. clientId: string · visitorId?: string · deal_id: string · deal_title: string · value_pence: number · from_stage_id: string|null · to_stage_id: string · from_stage: string|null · to_stage: string|null

deal.updated

open payload

A person changed a field on a deal in SIGNL: a custom field, the value or the expected close date. One event per field. Sent only for a deal that has a lead. clientId: string · visitorId?: string · deal_id: string · deal_title: string|null · field: string · from: string|null · to: string|null

deal.outcome_updated

A deal's outcome changed: open, won or lost, including a reopen. Fires only on a real change. clientId: string · dealId: string · status: string · previousStatus: string · visitorId: string|null · title: string|null · valuePence: number|null

deal.went_stale

open payload

An open deal has had no activity for the configured number of days. Sent once per quiet spell. clientId: string · visitorId?: string · deal_id: string · deal_title: string · value_pence: number · stage_id: string · stage: string|null · stale_days: number · idle_days: number · last_activity_at: string

payment

payment.received

A payment arrived (Stripe, Whop, Commas or Ablefy, or one recorded by hand). Renewals use the same event. clientId: string · visitorId: string|null · amountPence: number · source?: string · stripeEventType?: string · invoiceId?: string · paymentId?: string · currency?: string · productName?: string

payment.refunded

A payment was refunded, fully or in part. clientId: string · visitorId: string|null · amountPence: number · cumulativePence: number · isFullRefund: boolean · chargeId: string · source: string

payment.dispute.opened

A customer disputed a payment. clientId: string · visitorId: string|null · amountPence: number · chargeId: string · disputeId: string · disputeStatus: string · disputeReason: string|null · source: string

payment.dispute.resolved

A payment dispute was decided. clientId: string · visitorId: string|null · amountPence: number · chargeId: string · disputeId: string · disputeStatus: string · disputeReason: string|null · lost: boolean · source: string

payment.failed

open payload

A payment attempt failed. clientId: string · visitorId?: string · invoice_id?: string · amount_due_pence?: number

payment.deposit_received

open payload

A deposit on a deal was received. clientId: string · visitorId?: string · deal_id: string · deal_title: string · amount_pence: number · paid_pence: number · outstanding_pence: number · progress_pct: number · source_event_id?: string

payment.matched

A payment was linked to a lead, deal or call: a suggestion confirmed, a manual assignment, or a confident automatic match. clientId: string · paymentId: string · matchId: string|null · matchedTo: string|null · matchedId: string|null · confidence: number|null · source: string

payment.unmatched

A payment's link to a lead, deal or call was removed. clientId: string · paymentId: string

form

form.submitted

A SIGNL form was submitted. clientId: string · formId: string · visitorId: string|null · formSlug: string · qualified: boolean|null · endingId: string|null

report

report.submitted

A team member submitted an end-of-day report. reportId: string · clientId: string · repName: string · templateName: string · cadence: string · reportDate: string · callId: string|null · answers: array

lead

lead.tag_added

open payload

A tag was added to a lead. clientId: string · visitorId?: string · tag: string · source?: string · form_id?: string

lead.tag_removed

open payload

A tag was removed from a lead. clientId: string · visitorId?: string · tag: string

lead.updated

open payload

A person changed a field on a lead in SIGNL: a custom field, the name, the owner or a social handle. One event per field. Changes made by an automation, an import, the Agent or an API key are not announced. clientId: string · visitorId?: string · field: string · from: string|null · to: string|null

lead.hot

A lead crossed the workspace's hot-lead score. Sent once per lead per 25 hours. clientId: string · visitorId: string · leadName: string|null · email: string|null · score: number · threshold: number · source: string|null · signals: array · aiRead: string|null · leadUrl: string|null

contract

contract.signed

open payload

A contract sent to a lead was signed. clientId: string · visitorId?: string

contract.declined

open payload

A contract sent to a lead was declined. clientId: string · visitorId?: string

contract.expired

open payload

A contract sent to a lead expired unsigned. clientId: string · visitorId?: string

contract.viewed

open payload

A signer opened and read a contract sent to a lead. Once per signer. clientId: string · visitorId?: string

checkout

checkout.abandoned

open payload

A checkout was started and not completed. clientId: string · visitorId?: string

membership

membership.started

open payload

A membership or subscription started (Whop or Stripe). clientId: string · visitorId?: string · amount_pence?: number · currency?: string

membership.cancelled

open payload

A membership or subscription was cancelled (Whop or Stripe). clientId: string · visitorId?: string · membership_id?: string · product_name?: string

booking

booking.disqualified

open payload

Someone was screened out on a booking page. clientId: string · visitorId?: string

routing

routing.lost

open payload

A lead was routed to a calendar that had no times free. Sent once per lead. clientId: string · visitorId?: string · form_id: string · submission_id: string · booking_page_id?: string|null · booking_page_slug?: string|null · loss_reason: string

sms

sms.received

open payload

A text message came in from a lead. clientId: string · visitorId?: string · from?: string · body?: string

sms.failed

open payload

A text message to a lead failed to deliver. clientId: string · visitorId?: string

email

email.bounced

open payload

An email to a lead bounced. clientId: string · visitorId?: string

email.complained

open payload

A lead marked an email as spam. clientId: string · visitorId?: string

recording

recording.watched

open payload

A shared recording was watched. clientId: string · visitorId?: string

recording.cta_clicked

open payload

A lead clicked the call-to-action button on a recording sent to them. clientId: string · visitorId?: string

webinar

webinar.registered

open payload

Someone registered for a webinar. clientId: string · visitorId?: string · webinar_id: string · registration_id: string · lead_email?: string|null

webinar.attended

open payload

A registrant attended a webinar. clientId: string · visitorId?: string · webinar_id: string · registration_id: string · lead_email?: string|null

webinar.cta_clicked

open payload

A viewer clicked a webinar call to action. clientId: string · visitorId?: string · webinar_id: string · registration_id: string · lead_email?: string|null

webinar.replay_expiring

open payload

A webinar replay is about to expire for a registrant. clientId: string · visitorId?: string · webinar_id: string · registration_id: string · lead_email?: string|null

webinar.replay_expired

open payload

A webinar replay expired for a registrant. clientId: string · visitorId?: string · webinar_id: string · registration_id: string · lead_email?: string|null

This page is generated from the same list the product runs on, so it is never out of date. Something missing or unclear? Get help.