Milly Software
InsightsLeadsCustom Webhook Lead Routing — Send Leads to Any CRM
Leads··8 min read

Custom Webhook Lead Routing — Send Leads to Any CRM

Beyond Maestra and HubSpot. Wire your widget leads to any system that accepts a JSON POST.

V
Viet Le
co-founder · Milly Software

Why a Webhook?

Milly Chat stores every captured lead in its own database and can route them to platforms like Maestra. But many merchants use internal CRMs, Slack channels, Zapier automations, or custom tools that don't have a native integration.

The Custom Webhook solves this without requiring us to build integrations for every possible destination. You give us a URL, we POST to it every time a lead is captured. Your endpoint does whatever you want with the data—create a CRM record, send a Slack notification, trigger a Zapier workflow, update a spreadsheet.

The webhook fires alongside your existing lead platform routing, not instead of it. Using Maestra? The lead goes to Maestra AND your webhook. Using just Milly Chat? The lead stays in our database AND fires your webhook. They're composable.

Setting It Up

Navigate to Configure → Lead Capture and scroll past your platform and coupon settings to the Custom Webhook section.

  1. Toggle Enable webhook on
  2. Enter your Webhook URL (must be HTTPS)
  3. Optionally add Custom Headers (e.g., an Authorization bearer token)
  4. Optionally customize the Body Template (or leave blank for the default JSON)
  5. Click Save Changes
Custom Webhook configuration section with URL, headers, and body template fields

The Default JSON Body

If you leave the body template blank, we send a stable JSON object with every lead field:

{
  "email": "[email protected]",
  "name": "Jane Doe",
  "body": "Interested in wholesale pricing for 500 units",
  "intent": "business",
  "page_url": "https://yourstore.com/products/widget-pro",
  "conversation_id": "conv-abc-123",
  "coupon_code": null,
  "store_id": "store-uuid",
  "captured_at": "2026-04-15T14:30:00.000Z"
}

This works out of the box for most endpoints. If your destination expects a different format, use a custom body template with {{var}} placeholders.

Custom Body Templates

For Slack, you need a specific JSON shape. For a form-encoded endpoint, you need key=value pairs. The body template lets you format the payload however your destination expects:

// Slack incoming webhook
{
  "text": "New lead from {{email}} ({{intent}}): {{body}}"
}

// Form-encoded
email={{email}}&name={{name}}&source=milly_chat

Available variables: {{email}}, {{name}}, {{body}}, {{intent}}, {{pageUrl}}, {{conversationId}}, {{couponCode}}, {{storeId}}, {{capturedAt}}. Missing variables render as empty strings.

How It Behaves

  • Fire-and-forget with a 5-second timeout. Slow webhooks never block the chat response.
  • Fails silently. If your endpoint returns an error or times out, the chat continues normally and the lead is still saved in our database.
  • Fires for every intent—promotional, business, support, and general captures all trigger the webhook.
  • Custom headers let you pass Authorization tokens, API keys, or any header your endpoint expects. Content-Type defaults to application/json unless you override it.

Common Destinations

  • Slack — Use a Slack incoming webhook URL with the Slack JSON format
  • Zapier — Point at the trigger URL of a "Catch Hook" step in your Zap
  • Make.com — Use a "Custom webhook" trigger module URL
  • HubSpot / Salesforce / Pipedrive — Use their respective webhook/API endpoints with an Authorization header
  • Google Sheets — Route through Zapier or Make to append rows

If it accepts an HTTPS POST, it works.

Try Milly Chat

Want to see how this fits your store?
We'll set up a working session.

Get it on ShopifyTalk to sales →