Webhooks
10ex emits webhooks for CRM events, agent run lifecycle, and sequence/campaign milestones. Subscribe via Settings, Developers, Webhooks in the product, or programmatically through the flows module’s ExternalTrigger resource.
Event types
| Type | When |
|---|---|
lead.created | A new lead is added (any source: UI, API, connector, form, flow) |
lead.updated | Lead status, score, or fields change |
agent.run.started | A crew execution starts |
agent.run.completed | Crew execution finishes (success or failure) |
sequence.email.sent | A single email in an email sequence is delivered |
sequence.email.replied | Reply received on a sequence email |
connector.oauth.completed | OAuth flow finished, connector now usable |
Payload shape
{
"id": "evt_uuid",
"type": "lead.created",
"company_id": "uuid",
"occurred_at": "2026-05-05T10:00:00Z",
"data": { "lead_id": "uuid", "..." : "..." }
}id is unique per delivery attempt within a window, so you can dedupe safely in your handler.
Delivery and retries
- HTTP POST with a JSON body
- Signed via
X-10ex-Signature: sha256=<hex>(HMAC of the body with your workspace webhook secret) - Retried up to 5 times with exponential backoff on any non-2xx response
How to verify the signature
Compute HMAC-SHA256 of the raw request body using your webhook secret, hex-encode it, and compare to the X-10ex-Signature header. Use a constant-time comparison; a naive == opens you to timing attacks. The raw body matters; reserializing the JSON breaks the signature.
Common gotchas
A few things bite people on first integration:
- Verify against the raw body, not a re-parsed object. Ordering and whitespace matter.
- Idempotency is on you. Deliveries can repeat; key off
idin your handler. - Return a 2xx within 30 seconds. Long-running work belongs in a background queue your handler enqueues.
- 401 or 403 responses don’t get retried. Make sure your endpoint isn’t gated by an auth scheme that rejects 10ex’s POSTs.
Last updated on