Skip to content

Leads & CRM export

The AI gives every conversation a lead score from 0 to 100. A visitor appears in Leads when:

  • the score is 50 or higher, and they left an email or phone, or are signed in on your site (identified); or
  • your team marked them as a lead from the conversation (Marked by team).

Show anonymous also lists visitors with buying intent who left no contact and are not signed in. They are a demand signal, but there is nobody to follow up with, so they are never sent to the CRM webhook.

Not a lead hides a visitor for good: they disappear from Leads, CSV export and the CRM webhook, even if a later conversation scores high. You can mark them as a lead again from the conversation.

Export CSV on the Leads page downloads feedbot-leads-YYYY-MM-DD.csv with the current filters (bot, search, Show anonymous), up to 10,000 rows, newest first. It is UTF-8 with a BOM, so it opens correctly in Excel.

Column Value
First Name, Last Name, Full Name The name is split on the first space.
Email, Phone As left by the visitor.
Country Country name.
Company From identify metadata: company, companyName, company_name, organization or organisation.
Lead Source Feedbot · <bot name>
Lead Score The highest score of the visitor and their last 5 conversations.
Summary AI summary of the conversation.
Conversation URL, Page URL Link to the conversation in Feedbot and the page the visitor was on.
First Seen, Last Seen YYYY-MM-DD HH:MM:SS, UTC.

Leads → Send leads to CRM sends each new lead to an HTTPS URL of your choice: Zapier, Make, n8n, HubSpot or your own backend. There is one webhook per workspace, for all bots. The CRM webhook is available on Pro and Business; CSV export works on every plan.

  1. Enter the URL and save. In Zapier use Webhooks by Zapier → Catch Hook, in Make use Webhooks → Custom webhook, and paste the URL they give you. Feedbot generates a signing secret (whsec_...). You can copy or regenerate it in the same dialog.
  2. Click Send test lead to send a sample with "test": true, then map the fields in your Zap or scenario.
  3. Turn on Send new leads automatically.

Only leads that appear after you turn it on are sent. Use Export CSV for older leads. Anonymous leads are never sent.

  • right after a conversation is analyzed and the visitor qualifies as a lead;
  • right away when your team marks a visitor as a lead (in the dashboard, through the API or MCP), even if the visitor hasn’t been active for a long time. Marking never waits for your endpoint: the lead is queued and sent in the background within seconds.

Each lead is sent once. If your endpoint doesn’t answer with a 2xx status within 15 seconds, the lead is retried every few minutes for as long as the visitor was active, or was marked as a lead, in the last 7 days. The dialog shows the last error.

POST with Content-Type: application/json, X-Feedbot-Event: lead.created, X-Feedbot-Delivery (the event id) and an X-Feedbot-Signature header. The body uses the same envelope as notification webhooks:

{
"id": "evt_4c1d…",
"version": 2,
"type": "lead.created",
"createdAt": "2026-09-29T10:16:05Z",
"data": {
"id": "0b6f…",
"name": "Ann Smith",
"firstName": "Ann",
"lastName": "Smith",
"email": "[email protected]",
"phone": "+1 555 010 2030",
"country": "US",
"leadScore": 85,
"summary": "Team of 5, wants Pro yearly, asked about SSO.",
"bot": { "id": "5521cdf1-…", "name": "Acme" },
"conversationId": "9f0c…",
"conversationUrl": "https://app.feedbotai.com/c/9f0c…",
"pageUrl": "https://acme.io/pricing",
"firstSeenAt": "2026-09-29T10:02:11Z",
"lastSeenAt": "2026-09-29T10:15:40Z"
},
"lead": { "…": "the same object as data (deprecated)" }
}
  • data is the lead. data.id is the visitor id. Use it to deduplicate.
  • lead repeats data for integrations built before the envelope; new code should read data.
  • Missing text fields are empty strings. country is a two-letter code.
  • conversationId, conversationUrl, pageUrl and summary come from the visitor’s latest conversation.
  • test: true is present only on test sends.

X-Feedbot-Signature looks like t=1790000000,v1=5f2c…. v1 is the hex HMAC-SHA256 of "<t>.<raw body>" with your secret. Verify it against the raw body and reject old timestamps.

Node.js (Express)
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";
const app = express();
app.post("/feedbot/leads", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("X-Feedbot-Signature") ?? "";
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const t = Number(parts.t);
const body = req.body.toString("utf8");
const expected = createHmac("sha256", process.env.FEEDBOT_WEBHOOK_SECRET!).update(`${t}.${body}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - t) <= 300;
const valid = !!parts.v1 && expected.length === parts.v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
if (!fresh || !valid) return res.status(401).end();
const { data: lead, test } = JSON.parse(body);
// Create or update the contact in your CRM by lead.id / lead.email.
res.status(200).end();
});

The same signature scheme is used by the notification webhook.

On Pro and Business you can work with leads from code or from an AI agent. Keys need the leads:read scope to read and leads:write to mark leads (or read / write). See API & MCP for the full reference.

Method Path Description
GET /v1/leads Leads, most recently seen first. Filters: botId, q, includeAnonymous, marked, since, limit, cursor.
GET /v1/leads/{id} One lead by visitor id.
GET /v1/leads/export.csv The CSV export above, with the same filters.
POST /v1/leads/{id}/status {"status": "lead"} or {"status": "not_lead"}. Answers at once with export: queued (sent to the CRM webhook in the background), skipped or not_configured.

MCP tools: list_leads, get_lead and mark_lead.

CLI:

Terminal window
npx feedbot leads # table of leads
npx feedbot leads --bot BOT_ID --q acme --anonymous --json
npx feedbot leads --csv > leads.csv # same CSV as Export CSV
npx feedbot lead VISITOR_ID lead # or: not-lead