Lead webhook

Instagram leads, to Zapier,
Make, n8n or Google Sheets.

When someone comments a keyword or sends you a DM, Chat33 asks for their email in the chat. Every email it collects is sent as JSON to a webhook URL within seconds, and your automation tool puts it wherever you want: a Google Sheets row, Airtable, Notion, Slack or your CRM.

Available on every plan, including Free. Workspace owners and admins can connect it.

What happens

  1. 1Someone comments GUIDE under your post
  2. 2Chat33 sends them a DM asking for their email
  3. 3They reply with their email address
  4. 4Chat33 POSTs the lead to your webhook URL
  5. 5Your Zap, scenario or workflow adds it to Google Sheets
Before you start

What you need

Three things. No Chat33 app is needed in your automation tool: it is a plain webhook.

A connected Instagram or Facebook account

An Instagram professional account (business or creator) or a Facebook Page, connected in Chat33 under Channels.

A flow with a Collect email step

The step asks for the email in a DM and waits up to 24 hours for the answer. It works with DM keyword triggers on Instagram and Facebook, and with comment triggers on Instagram. Asking after a Facebook comment is not available yet.

A tool that can receive a webhook

Zapier (Webhooks by Zapier needs a paid Zapier plan), Make, n8n, or your own server. The address must be public and start with https://. In Chat33, workspace owners and admins can set the webhook.

Setup

Set it up in six steps

Keep your automation tool and Chat33 open in two tabs. You copy one URL from one to the other.

  1. 1

    Get a webhook URL in your tool

    Create a new automation that starts with a webhook, then copy the URL it gives you.

    • Zapier: create a Zap, pick Webhooks by Zapier as the trigger app and Catch Hook as the event, then copy the webhook URL.
    • Make: create a scenario, add the Webhooks module Custom webhook, click Add, name it and copy the address.
    • n8n: add a Webhook node and set HTTP Method to POST. Copy the Test URL for now. For real leads use the Production URL and activate the workflow.
  2. 2

    Paste it into Chat33

    In Chat33, go to Settings, API Keys and find the Message webhook card. Paste the URL in the address field.

  3. 3

    Choose New leads

    Under Send, tick New leads. Untick New DMs if you only want leads, otherwise every DM people send you goes to the same URL. Leave All accounts in this workspace selected, or pick the accounts whose leads you want. Click Save.

  4. 4

    Send a test lead

    Click Send test lead. Chat33 sends a made up lead (Ana Lopez, ana@example.com) with "test": true, and the card shows the HTTP status your tool answered with. In Zapier click Test trigger, in Make wait for the module to say it determined the data structure, in n8n click Listen for test event before you send.

  5. 5

    Map the fields

    Add the next step and map the lead's fields into it. For Google Sheets: in Zapier use Create Spreadsheet Row, in Make Add a Row, in n8n the Google Sheets node with Append Row. Put data.email, data.name, data.username, data.flow.name and data.capturedAt in their own columns, or whatever you need. Skip or filter out requests where test is true.

  6. 6

    Turn it on and check a real lead

    Publish the Zap, turn on the scenario or activate the n8n workflow, and switch your Chat33 flow on. Test the flow from a second Instagram account. The Zapier, Make, n8n, Google Sheets card in Settings, Integrations shows how many leads were sent, are waiting or failed, and Delivery log lists the last 50.

Example request

What your tool receives

One POST per lead, with a JSON body. This is a real request from Send test lead, word for word.

Headers
content-type: application/json
user-agent: Chat33-Webhooks/1.0
x-chat33-event: lead.captured
x-chat33-signature: t=1793009626,v1=0decb33a96de935324152cb242ec33c3c45849853d59e1ff330b20cb89ded992
Body
{
  "event": "lead.captured",
  "id": "evt_lead_test_1793009626943",
  "createdAt": "2026-10-26T10:13:46.944Z",
  "data": {
    "version": 1,
    "captureKey": "test_1793009626943",
    "email": "ana@example.com",
    "name": "Ana Lopez",
    "firstName": "Ana",
    "lastName": "Lopez",
    "username": "ana.lopez",
    "platform": "instagram",
    "platformId": "test_platform_id",
    "contactId": "test_contact",
    "channel": {
      "id": "test_channel",
      "name": "Test account"
    },
    "flow": {
      "id": "test_flow",
      "name": "Test flow"
    },
    "keyword": "guide",
    "postId": null,
    "postUrl": null,
    "tags": [],
    "question": "What is your email?",
    "capturedAt": "2026-10-26T10:13:46.943Z",
    "firstSeenAt": "2026-10-26T10:13:46.943Z"
  },
  "test": true
}
What gets sent

Every field

Nested under data, except the first four. Fields are only ever added, never renamed or removed, and data.version tells you the shape.

event
Always lead.captured for a lead. The same value is in the X-Chat33-Event header.
id
The event id, evt_lead_ followed by the capture key. It stays the same if the same lead is delivered again (a retry or Send existing leads), so use it to skip duplicates.
createdAt
When this request was made. A retry gets a new createdAt, the id stays.
test
true on Send test lead. Real leads do not have this field.
data.version
The payload version, 1 today.
data.captureKey
One key per person, email address and flow. A person who gives the same address to the same flow again is not sent again. Test leads have a key that starts with test_.
data.email
The address they wrote in the DM.
data.name, data.firstName, data.lastName
Their name on Instagram or Facebook, and the same name split in two. First and last name stay null when all we know is their handle.
data.username
Their handle, without the @. null when the platform does not give one.
data.platform, data.platformId
Where the lead came from (instagram or facebook) and the person's id there, the id Meta gives them for your account.
data.contactId
The contact's id in Chat33, the same id the REST API uses.
data.channel
The connected account the lead wrote to: id and name.
data.flow
The flow that asked for the email: id and name, as they were when the email came in.
data.keyword
The keyword that started the flow, or null.
data.postId, data.postUrl
The post they commented on, when a comment started the flow. postUrl is filled in only for posts published through Chat33, otherwise null.
data.tags
The contact's Chat33 tags when the email came in. Often an empty list.
data.question
The question the Collect email step sent, as the person saw it.
data.capturedAt, data.firstSeenAt
When they gave the email, and when the contact first appeared in Chat33. ISO 8601, UTC.

Chat33 never emails your leads. What happens next is up to the automation you build.

Security

Check that a request came from Chat33

Every request is signed with your webhook's signing secret, shown on the Message webhook card in Settings, API Keys. No-code tools can skip this step and keep the webhook URL private. On your own server, check the signature before you trust the body.

X-Chat33-Event

lead.captured for a lead, message.received for a DM.

X-Chat33-Signature

Looks like t=1793009626,v1=0decb33a..., where t is the Unix time in seconds and v1 is the HMAC-SHA256 of the timestamp, a dot and the raw request body, keyed with the whole signing secret (whsec_...). Each attempt is signed again with a fresh timestamp.

User-Agent

Chat33-Webhooks/1.0, with Content-Type application/json.

A new secret

Removing the webhook and saving it again makes a new secret. Update your server when that happens.

Node.js (Express)
const crypto = require("crypto");
const express = require("express");

// Settings, API Keys, Message webhook, Signing secret (whsec_...)
const SECRET = process.env.CHAT33_WEBHOOK_SECRET;

function verifyChat33(rawBody, header, toleranceSeconds = 300) {
  const parts = {};
  for (const piece of String(header || "").split(",")) {
    const i = piece.indexOf("=");
    if (i > 0) parts[piece.slice(0, i)] = piece.slice(i + 1);
  }
  if (!parts.t || !parts.v1) return false;
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > toleranceSeconds) return false;
  const expected = crypto
    .createHmac("sha256", SECRET)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(parts.v1, "hex");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

const app = express();

// The raw body: the signature covers the exact bytes Chat33 sent.
app.post("/chat33-webhook", express.raw({ type: "application/json" }), (req, res) => {
  const rawBody = req.body.toString("utf8");
  if (!verifyChat33(rawBody, req.get("X-Chat33-Signature"))) return res.sendStatus(401);

  const event = JSON.parse(rawBody);
  if (event.event === "lead.captured" && !event.test) {
    // Save event.data.email, skip event.id values you already have.
  }
  res.sendStatus(200);
});

app.listen(3000);
Options

How delivery works

What Chat33 does with each lead, and what your endpoint should answer.

Answer with a 2xx within 10 seconds

Any 2xx status counts as delivered. Anything else, a timeout after 10 seconds or a network error counts as a failure. Redirects are not followed, so save the final address.

Failed leads are retried

A failed lead is tried again after about 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours. After that it shows as Failed, and Retry failed on the card sends it again. A 429 answer means wait: Chat33 tries again a minute later without using up a retry.

Test leads are sent once

Send test lead makes one attempt, is not retried and does not appear in the delivery log. It is sent even when New leads is not ticked, so tick it before you rely on real leads.

The same webhook can send DMs

With New DMs ticked, the same URL also gets message.received for every DM people send your connected accounts, so your own bot can answer them. The API reference describes that event and the webhook endpoints.

Leads you already have

Send existing leads

Leads you collected before turning on New leads are not sent on their own. Click Send existing leads on the Zapier, Make, n8n, Google Sheets card in Settings, Integrations and they go out over the next few minutes, with the same ids as before, so your tool can skip any it already has.

Troubleshooting

When nothing arrives

Chat33 keeps every lead, so fixing the webhook is enough. Nothing has to be collected again.

Check the Message webhook card

The URL must be saved and New leads ticked. The card shows the last delivery with its HTTP status or the error. Send test lead to see the answer right away.

Zapier says the app needs an upgrade

Webhooks by Zapier is not on the free Zapier plan. Upgrade, or use Make or n8n, which can receive webhooks on their free plans.

Your tool answers with an error

A 4xx or 5xx answer is a failure and the lead is retried. In n8n the Test URL only works while you are listening for a test event: use the Production URL with the workflow active. In Make, the scenario must be on.

The address was not accepted

Chat33 only sends to public https:// addresses. A self-hosted n8n on localhost or a private network cannot receive leads. Remove anything after a # in the URL.

Leads are in Chat33 but not in your tool

Open Delivery log on the Zapier, Make, n8n, Google Sheets card. Each lead shows its status and the reason. Leads from accounts the webhook does not cover are skipped, and leads collected before you turned on New leads need Send existing leads.

Nobody was asked for an email

Check the flow. It must be switched on, and when it starts from an Instagram comment, the Collect email step must come before the first DM. Asking after a Facebook comment is not available yet.

Questions about the lead webhook

Is there a Chat33 app in Zapier or Make?
Not yet. You use the webhook trigger every automation tool has: Webhooks by Zapier, Catch Hook in Zapier, Custom webhook in Make, the Webhook node in n8n. For n8n there is also an official Chat33 node for posting and other API actions.
Which Chat33 plans include the lead webhook?
Every plan, including Free. Your automation tool may need a paid plan of its own, as Zapier does for webhooks.
How fast do leads arrive?
Usually within seconds of the person sending their email. If your endpoint is down, Chat33 keeps the lead and tries again.
Can I send leads to Google Sheets without Zapier or Make?
Not directly. Google Sheets cannot receive a webhook by itself, so a tool such as Zapier, Make or n8n sits in between and adds the row.
Will the same lead arrive twice?
A person who gives the same address to the same flow is sent once. A retry or Send existing leads can deliver a lead again, with the same id, so de-duplicate on id or on data.email.
Can I use the webhook and Mailchimp or HubSpot at the same time?
Yes. Every new lead goes to each connected destination.
How do I tell a test lead from a real one?
Test leads have "test": true at the top level and the address ana@example.com. Real leads have no test field.
Chat33 mascot holding a Get it here button

Turn comments into
rows, records and alerts.

Create a free account, connect Instagram, add a Collect email step and paste your webhook URL.