Skip to content

CRM Webhook

Endpoint: POST /webhooks/crm/lead

Accepts lead change events from the CRM (or from Make.com as a proxy). The payload is matched to our lead by crm_lead_id (looked up in Leads first, then in LeadSubmissions for follow-up leads). When a match is found, the event is stored in LeadCrmActivity and exposed in the lead detail API and dashboard timeline.

Authentication

Requires CRM_WEBHOOK_SECRET (or CRM_CALLBACK_SECRET if CRM_WEBHOOK_SECRET is not set). Send via:

  • Authorization: Bearer <secret>, or
  • X-API-Key: <secret>

Requests without a valid secret receive 401 Unauthorized. If neither secret is configured, the endpoint returns 503 Service Unavailable.

Request

  • Method: POST
  • Content-Type: application/json
  • Body:
json
{
  "crm_lead_id": "crm-abc-456",
  "event_type": "status_changed",
  "status": "qualified",
  "updated_at": "2026-03-05T10:00:00Z"
}
FieldTypeRequiredDescription
crm_lead_idstringYesCRM lead ID (must match Leads.CrmLeadId or LeadSubmissions.CrmLeadId).
event_typestringNoEvent type (e.g. created, updated, status_changed). Default: updated.
(any)NoAdditional fields are stored as JSON in LeadCrmActivity.PayloadJson.

The full request body is stored in PayloadJson so the dashboard or downstream consumers can use it.

Lookup behaviour

  1. Look up Leads by CrmLeadId. If found, use that lead’s row ID for LeadCrmActivity.LeadId.
  2. If not found, look up LeadSubmissions by CrmLeadId (most recent by SubmittedAt). If found, use that submission’s LeadId for LeadCrmActivity.LeadId.
  3. If no match, the webhook returns 200 OK with stored: false so the CRM does not retry; the event is logged for debugging.

Response

200 OK — Event stored:

json
{
  "ok": true,
  "stored": true,
  "lead_id": 123
}

200 OK — No matching lead/submission (event not stored):

json
{
  "ok": true,
  "stored": false,
  "reason": "No matching lead or submission for crm_lead_id"
}

400 Bad Request — Missing or invalid crm_lead_id, or invalid JSON.

401 Unauthorized — Missing or invalid secret.

500 Internal Server Error — Database error while inserting.

503 Service Unavailable — CRM webhook secret not configured.

Integration (CRM or Make.com)

  1. In the CRM (or Make.com), configure a webhook or HTTP request to fire when a lead is created, updated, or status-changed.
  2. URL: https://<your-worker>/webhooks/crm/lead
  3. Method: POST
  4. Headers: Authorization: Bearer <CRM_WEBHOOK_SECRET> (or CRM_CALLBACK_SECRET) or X-API-Key: <secret>
  5. Body: Include at least crm_lead_id; add event_type and any other fields as needed. The entire body is stored for the lead’s activity timeline.

CRM activity is returned by GET /analytics/leads/:id in the crm_activity array and shown in the dashboard lead detail timeline with a “CRM” label.