Notifications via API: leads and bot alerts to your server
If leads should land in your own system (a custom CRM, Make, n8n, Zapier or any server), turn on API in the bot's notifications. You enter an HTTPS URL and the platform sends it a JSON POST request: for every new lead and its updates, when the bot needs a human, and when tokens are running out. Every request is signed with a secret so your server can check that it came from BotB2B.
What notifications arrive
| event | When | What is inside |
|---|---|---|
lead.created | The bot captured a new lead | The customer's contacts, a summary and the conversation, chat links |
lead.updated | The lead got new details: a phone number, a comment, a new status | The same lead with the same data.lead.id: update the record on your side |
chat.help_needed | The bot called a human and paused in this chat | reason: bot_asked when the bot could not handle it, messages_limit when the conversation hit the message limit |
tokens.low | The token balance is running low | tokensRemaining: how many are left |
tokens.depleted | Tokens ran out: bots stop replying to customers | — |
tokens.bot_silent | A bot did not reply to a customer because of the balance (at most once a day) | integrationId and integrationName: the account where the bot stayed silent |
test | You pressed Test in the settings | A sample lead |
Token events are about the whole account balance, not a single bot, so they go to the URLs of every bot with API turned on. Several bots with the same URL get one request.
How to connect
- 1
Open the bot's notifications
Go to Front Desk → Bots, pick the bot and open the Notifications tab. In the API row press Configure notifications.
- 2
Paste the receiver URL
In Receiver URL enter the address that accepts POST requests: your CRM endpoint, a Make or n8n webhook trigger, or a Zapier Catch Hook. The URL must start with
https://. - 3
Press Test
A sample lead with the
testevent is sent to the URL. Below the button you see the response code, the time and the start of your server's reply. A 2xx code means it works. You do not need to save the URL before testing.Test runs at most 5 times per minute per bot, so setting it up never turns into a flood of requests to someone else's server.
- 4
Save
Press Save: the API row in the notifications list turns to Notifications configured. To stop sending, press Turn off in the same window.
Only HTTPS URLs are accepted. Internal and local addresses (localhost, 10.x, 192.168.x and so on) are rejected: the receiver must be reachable from the internet.
Request format
Method POST, body JSON in UTF-8. The notification kind is in the event field and the X-Webhook-Event header. The type field stays for compatibility with older integrations (lead_new, lead_update, bot_chat_have_mistake, tokens_threshold, tokens_depleted, bot_reply_no_balance, lead_test).
| Header | Value |
|---|---|
Content-Type | application/json |
X-Webhook-Event | The event, same as the event field (lead.created, chat.help_needed…) |
X-Webhook-Delivery | Unique request id, same as delivery_id in the body |
X-Webhook-Timestamp | Send time in ISO 8601 (UTC) |
X-Webhook-Signature | sha256=… signature, see below how to check it |
Lead: lead.created and lead.updated
{
"event": "lead.created",
"type": "lead_new",
"bot_id": "c8df2a84-9b17-4bf9-9248-9cee74eaeee6",
"data": {
"lead": {
"id": "9b2f6c1e-…",
"name": "Anna",
"phone": "+15551234567",
"email": "[email protected]",
"telegram_username": null,
"city": "Austin",
"address": null,
"scheduled_call": null,
"type_payment": null,
"need_delivery": null,
"delivery_time": null,
"meeting_date_time_office": null,
"meeting_date_time_client": null,
"extended_info": null,
"status": "NEW",
"comment": "Wants a quote for 3 rooms"
},
"botChatId": 12345,
"shortInfo": "Wants a renovation quote for three rooms, asks for a call in the evening",
"messages": "Client: …\nBot: …",
"linkToChat": "https://…",
"channelUrl": "https://…"
},
"timestamp": "2026-09-21T12:00:00.000Z",
"delivery_id": "3f1c2a4e-…"
}data.lead.idis the same inlead.createdand everylead.updatedof one lead: use it to update the record on your side.- Fields the bot did not collect come as
null. shortInfois the conversation summary,messagesis the transcript: short or full depending on the bot setting How to format the notification in Telegram?.linkToChatlinks to the conversation in the source channel when the platform provides one.
Help needed: chat.help_needed
{
"event": "chat.help_needed",
"type": "bot_chat_have_mistake",
"bot_id": "c8df2a84-9b17-4bf9-9248-9cee74eaeee6",
"data": {
"reason": "bot_asked",
"botId": "c8df2a84-9b17-4bf9-9248-9cee74eaeee6",
"botChatId": 12345,
"shortInfo": "The client asks about a custom order",
"messages": "Client: …\nBot: …",
"linkToChat": "https://…"
},
"timestamp": "2026-09-21T12:05:00.000Z",
"delivery_id": "…"
}The bot in this chat has already paused and is waiting for a human: open the conversation via linkToChat or in Chats and reply to the customer yourself.
Token balance: tokens.*
{
"event": "tokens.low",
"type": "tokens_threshold",
"bot_id": "c8df2a84-9b17-4bf9-9248-9cee74eaeee6",
"bot_ids": [
"c8df2a84-9b17-4bf9-9248-9cee74eaeee6",
"5e0a7d31-…"
],
"data": {
"tokensRemaining": 50000
},
"timestamp": "2026-09-21T13:00:00.000Z",
"delivery_id": "…"
}Token events arrive once per URL: bot_ids lists every bot with this URL and bot_id is the bot whose secret signed the request. Use tokens.low to top up in time, and treat tokens.depleted and tokens.bot_silent as alarms: customers are left without an answer.
Verifying the signature
The signing secret is in the same window, in the Signing secret block (Show and Copy buttons). Each bot has its own secret. The signature is HMAC-SHA256 of the string X-Webhook-Timestamp + . + the raw request body, keyed with the secret, in hex with the sha256= prefix. Compute it over the body before parsing JSON: re-serialized JSON may not match byte for byte.
import crypto from "node:crypto";
// rawBody: the request body as a string, BEFORE JSON.parse
function isValid(rawBody, headers, secret) {
const expected =
"sha256=" +
crypto
.createHmac("sha256", secret)
.update(headers["x-webhook-timestamp"] + "." + rawBody)
.digest("hex");
const got = headers["x-webhook-signature"] || "";
return (
got.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected))
);
}import hashlib, hmac
def is_valid(raw_body: bytes, headers, secret: str) -> bool:
message = headers["X-Webhook-Timestamp"].encode() + b"." + raw_body
expected = "sha256=" + hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, headers.get("X-Webhook-Signature", ""))To reject replays, compare X-Webhook-Timestamp with the current time (for example, no older than 5 minutes) and keep the delivery_id values you have processed.
If the secret leaks, press Generate new: the old one stops working immediately, so update it on your server.
Delivery and your response
- Respond with a 2xx code within 10 seconds. Do heavy processing after responding, in the background.
- Redirects are not followed: enter the final URL.
- Failed requests are not retried. The API notification is lost, but the other channels (Telegram, email, CRM) still work and the lead stays in Leads.
- API works alongside the other channels, not instead of them: you can get leads in Telegram and in your system at the same time.
Does it work with Make, n8n or Zapier?
Yes. Create a scenario with a Webhook trigger (Catch Hook in Zapier), paste its HTTPS URL into the API field and press Test: the sample lead shows up in the scenario and you can map the fields from it.
Can several bots use one URL?
Yes. bot_id tells you which bot sent the notification. Each bot has its own secret: always verify the signature with the secret of the bot in bot_id, token events included.
Why is my URL rejected?
It needs https:// and a domain reachable from the internet. http:// URLs, localhost and internal IPs are rejected. For local development use a tunnel with an HTTPS address.
Can I set it up without the UI?
Yes, through the Front Desk MCP server: the bots tool, actions set_lead_webhook, test_lead_webhook and get_lead_webhook. See Connect the MCP server.
See also
Try BotB2B for free
Sign-up takes a minute and starter tokens are on us. Set everything up with this guide.