agentlyleads docs
Webhooks

Webhooks overview

A webhook tells your server that something happened in the CRM, a few seconds to a minute after it happened. You register an HTTPS URL and pick the events you want; agentlyleads sends each one as a JSON POST.

Use webhooks when you would otherwise poll GET /api/v1/...?updatedSince= on a timer. Use the API to read or change data; use webhooks to find out when to do it.

Add an endpoint

Two ways, both need the workspace owner or an API key with write:webhooks:

  • In the app: Settings, Developer, Webhooks. Enter the URL, tick the events, and copy the signing secret that appears.
  • With the API: POST /api/v1/webhooks.
curl https://agentlyleads.com/api/v1/webhooks \
  -H "Authorization: Bearer $AGENTLYLEADS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/agentlyleads",
    "events": ["lead.created", "deal.stage_changed"],
    "description": "Mirror new leads into billing"
  }'

The response includes secret (it starts with whsec_). It is shown once. Store it with your receiver's other secrets; you need it to verify signatures. If you lose it, rotate it.

Subscribe to ["*"] to get every event, including ones added later.

The URL must be public and use https. Hosts that are, or resolve to, private, loopback or link-local addresses (for example localhost, 10.x.x.x, 169.254.169.254) are refused, and redirects are not followed. To develop locally, expose your receiver through a tunnel such as ngrok or Cloudflare Tunnel.

What a request looks like

POST /agentlyleads HTTP/1.1
Host: hooks.example.com
Content-Type: application/json
User-Agent: AgentlyLeads-Webhooks/1.0 (+https://agentlyleads.com/docs/webhooks)
X-AgentlyLeads-Event: lead.created
X-AgentlyLeads-Delivery: cmq9dlvr0alk34567890
X-AgentlyLeads-Timestamp: 1790517600
X-AgentlyLeads-Signature: sha256=6f1c0b...e93a

{
  "id": "evt_5b1f0c7d2a9e4f6b8c3d1e0a",
  "type": "lead.created",
  "createdAt": "2026-09-27T14:00:00.000Z",
  "workspaceId": "cmq1wksp0alk34567890",
  "data": { "lead": { "id": "cmq2lead0alk34567891", "name": "Eve Park", "...": "..." } }
}
FieldMeaning
idThe event ID. The same event sent again (a retry or a redelivery) keeps the same id, so de-duplicate on it
typeThe event name. See Events
createdAtWhen the event happened, ISO 8601 UTC
workspaceIdThe workspace the event belongs to
dataThe payload. Records use the same shape the v1 API returns for them
HeaderMeaning
X-AgentlyLeads-EventSame as type
X-AgentlyLeads-DeliveryThe delivery ID. It stays the same across retries of this delivery; a manual redelivery gets a new one. Useful in support requests and for redelivery
X-AgentlyLeads-TimestampUnix seconds when this request was signed
X-AgentlyLeads-Signaturesha256= and a hex HMAC. See Verifying signatures

How to respond

Answer with any 2xx status within 10 seconds. The body is ignored. Anything else (a 3xx, 4xx or 5xx, a timeout, or a connection error) counts as a failure and the event is retried.

If your work takes longer than a few seconds, put the event on a queue and answer 200 straight away.

Things to know

  • Order is not guaranteed. Events are sent in batches every minute, several at a time, and retries go out later. Use createdAt and the record's updatedAt if order matters.
  • At least once. A network error after your server processed the request makes us send it again. De-duplicate on id.
  • Re-read when in doubt. A payload is a snapshot taken when the event was queued. For the current state, fetch the record from the API.
  • One change can raise several events. A booking from a new person, for example, sends lead.created, task.created and booking.created.
  • Limits. Up to 10 endpoints per workspace. Delivery history is kept for 30 days.

On this page