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

eventWhenWhat is inside
lead.createdThe bot captured a new leadThe customer's contacts, a summary and the conversation, chat links
lead.updatedThe lead got new details: a phone number, a comment, a new statusThe same lead with the same data.lead.id: update the record on your side
chat.help_neededThe bot called a human and paused in this chatreason: bot_asked when the bot could not handle it, messages_limit when the conversation hit the message limit
tokens.lowThe token balance is running lowtokensRemaining: how many are left
tokens.depletedTokens ran out: bots stop replying to customers
tokens.bot_silentA 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
testYou pressed Test in the settingsA 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. 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. 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. 3

    Press Test

    A sample lead with the test event 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. 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).

HeaderValue
Content-Typeapplication/json
X-Webhook-EventThe event, same as the event field (lead.created, chat.help_needed…)
X-Webhook-DeliveryUnique request id, same as delivery_id in the body
X-Webhook-TimestampSend time in ISO 8601 (UTC)
X-Webhook-Signaturesha256=… signature, see below how to check it

Lead: lead.created and lead.updated

json
{
  "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.id is the same in lead.created and every lead.updated of one lead: use it to update the record on your side.
  • Fields the bot did not collect come as null.
  • shortInfo is the conversation summary, messages is the transcript: short or full depending on the bot setting How to format the notification in Telegram?.
  • linkToChat links to the conversation in the source channel when the platform provides one.

Help needed: chat.help_needed

json
{
  "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.*

json
{
  "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.

Node.js
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))
  );
}
Python
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.

Notifications and CRMTelegram, email, the built-in CRM and amoCRM

See also

Try BotB2B for free

Sign-up takes a minute and starter tokens are on us. Set everything up with this guide.

Start for free