Register an endpoint, pick the events you want, and SealDeal POSTs a signed JSON envelope to your URL each time one fires. Verify the X-Outbound-Signature header before trusting a payload. There are 54 events you can subscribe to today, and a failed delivery is retried 6 times over roughly 24 hours before it is marked dead.
Every delivery has the same outer shape. Event-specific fields live under `data`, so you can route on `type` before parsing anything else.
POST https://your-endpoint.example.com/hooks
Content-Type: application/json
X-Outbound-Signature: t=1753027200,v1=9f86d081...
{
"apiVersion": "2026-07-21",
"id": "evt_01H...",
"type": "reply.received",
"createdAt": "2026-07-30T12:00:00.000Z",
"organizationId": "org_01H...",
"data": { }
}The header carries a timestamp and a hex HMAC-SHA256. The signed string is the timestamp, a literal dot, then the raw request body. Sign the raw bytes you received: re-serializing the parsed JSON will not reproduce the signature, which is the single most common reason a first integration fails.
import crypto from 'node:crypto'
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(
header.split(',').map((kv) => kv.split('='))
)
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex')
// Constant-time compare, never ===
const a = Buffer.from(expected, 'hex')
const b = Buffer.from(parts.v1, 'hex')
return a.length === b.length && crypto.timingSafeEqual(a, b)
}The signing secret is shown once when the endpoint is created and is stored only as a hash, so it cannot be recovered later. Rotate it with POST /api/v1/webhooks/{id}/rotate-secret if it leaks. Format: whs_ followed by 32 hex characters.
Each attempt times out after 10 seconds. Return any 2xx to acknowledge. A 5xx or a timeout is retried; a 4xx is treated as a permanent rejection and is not. There are 7 attempts in total, the first plus 6 retries:
Deliveries are inspectable over the API: list them with GET /api/v1/webhooks/{id}/deliveries, read one in full, and replay a failed one once your endpoint is healthy again. Endpoints that keep failing are disabled rather than retried forever.
Design your handler to be idempotent on the envelope `id`. Retries mean the same event can arrive more than once, and a handler that charges, emails or creates on every receipt will do so twice.
54 events fire today. 5 of them are `rule.*` events your own custom rules emit, so you can trigger on conditions you define rather than only on platform lifecycle.
Action items appearing on and leaving the rep work queue.
action.resolved
Account records and their research.
company.research_completed
Contact lifecycle and research.
contact.deleted · contact.erased · contact.snoozed · contact.stage_changed · contact.tagged
Pipeline movement, including stage transitions and terminal outcomes.
deal.created · deal.lost · deal.stage_changed · deal.won
demo.abandoned · demo.run · demo.signup_clicked
The outbound draft lifecycle, from generation through approval to send.
draft.approved · draft.created · draft.failed · draft.pending_approval · draft.sent
Delivery telemetry from the mail provider: opens, clicks, bounces, complaints.
email.bounced · email.clicked · email.complained · email.opened · email.unsubscribed
grounding.would_fire
handoff.created
inbound.lead_received
Inbound leads captured, qualified and routed.
lead.interested
Contact lists and their contents.
list.context_updated · list.uploaded
Meetings booked against a deal.
meeting.booked
Organization-level configuration changes.
org.health_changed · org.research_ttl_updated
quota.warning
Team membership changes.
rep.activated · rep.invited
Inbound replies and their classified intent.
reply.classified · reply.received
research.completed
Events a custom rule emits through its call_webhook action, so you can trigger on your own conditions rather than only on platform lifecycle.
rule.deal_at_risk · rule.hot_reply · rule.lead_qualified · rule.objection · rule.triggered
send.failed
Multi-step outreach state.
sequence.completed · sequence.paused · sequence.resumed · sequence.started · sequence.step_failed
Addresses and domains entering the do-not-contact list.
suppression.added · suppression.removed
team.member_added · team.member_removed
These 14 names are catalogued and accepted by the subscription API, but nothing emits them today. Subscribing to one is valid and will simply never deliver, so treat this list as a roadmap rather than a feature. They are listed here because a silent integration is worse than a missing one.
action.created · company.created · deal.risk_changed · draft.regenerated · list.contacts_added · meeting.cancelled · meeting.completed · meeting.scheduled · org.created · org.seller_profile_updated · payment.failed · quota.exceeded · subscription.canceled · subscription.changed
See also: Docs home · API reference · API errors · Integrations