Developers

Drive the chat from your code.

Pre-authenticate visitors so contacts are known, open and close the widget on demand, and stream support events to your stack — all from your existing JavaScript and server.

Quick start

Install

Paste this once in your site's <head>. Everything else is optional.

install.html
<!-- Paste once, just before </head> -->
<script async src="https://your-helpbird-host/api/embed?id=YOUR_PROJECT_ID"></script>

Replace YOUR_PROJECT_ID with your own project ID from Settings → Install. The async loader injects the chat button and iframe (it never blocks your page) and exposes a global window.HelpBird object. If the project is inactive or the widget is hidden, the script is an empty no-op — a stale tag never breaks the host page.

Method

HelpBird.identify()

Tell the widget who the visitor is so the conversation lands on a known contact — the email matches or creates the contact and attaches their cross-conversation history.

Signature

HelpBird.identify({ email, name?, user_id?, hmac? })

Parameters

  • user_id — your own identifier for the visitor. optional
  • email — used to match or create the contact and build their history. required
  • name — display name shown to your agents. optional
  • hmac — server-signed digest for verified identity. optional

Safe to call any time after the loader has run — the widget picks it up even if the visitor hasn't opened the chat yet.

example.html
<script>
  // Any time after the loader has run — one object:
  HelpBird.identify({
    email: "jane@acme.com",           // required — matches/creates the contact
    name: "Jane Doe",                 // optional — shown to your agents
    user_id: "your-internal-user-42", // optional — your own identifier
    hmac: "<hmac from your server>",  // optional — verified identity
  });
</script>
Method

open() & close()

Show or hide the chat widget from your own UI — wire it to a "Contact support" button, a help menu, or an exit-intent flow.

Methods

  • HelpBird.open() — open the widget panel.
  • HelpBird.close() — collapse the widget back to the launcher.

Both are safe to call any time after the loader has run.

support-button.html
<button onclick="HelpBird.open()">Contact support</button>
Server · Pro

Verified identity

Pre-authenticate your visitors with your existing login system. Sign the visitor's identifier server-side with your project's identity secret, pass the digest to identify, and the contact arrives already known — with a verified badge your agents can trust.

How it works

  • The digest is HMAC-SHA256(secret, identifier), hex-encoded. The identifier is the user_id you pass to identify(), or the email if you don't pass one.
  • The secret is in Settings → Install → Identity verification (account owner, Pro). Keep it server-side — never ship it in page JavaScript. Rotating it there invalidates every signature made with the old one.
  • On a valid signature the conversation is marked verified, so agents know exactly who they're helping.

Why use it

  • Visitors never re-type their name or email — the contact is known from the first message.
  • Only signed calls get the Verified badge. Unsigned calls still work but aren't marked verified, so agents can tell the difference.
  • Conversation history attaches to the right contact every time.
server.ts
// Sign once per page load, server-side.
import { createHmac } from "node:crypto";

// Identifier: your user_id if you pass one to identify(), else the email.
const hmac = createHmac("sha256", process.env.HELPBIRD_IDENTITY_SECRET)
  .update(String(user.id))
  .digest("hex");

// Render it into the page, then:
//   HelpBird.identify({ user_id: String(user.id), email: user.email, name: user.fullName, hmac });
Server · Pro

Webhooks

Subscribe to support events from outside the browser — Slack notifications, CRM sync, Zapier flows, custom analytics, anything. We POST a signed JSON payload; you verify the signature and process.

Configure

Settings → Webhooks. Add a URL, pick events, and keep the shared secret somewhere safe — it signs every delivery.

Events

  • message_posted — a new message from a visitor or an agent.
  • mention_received — a teammate is @mentioned in an internal note. data.mentions lists who.

Headers

  • Content-Type: application/json
  • X-Helpbird-Event — the event name (matches the body's event field).
  • X-Helpbird-Signature — hex-encoded HMAC-SHA256 over the raw request body, keyed with your shared secret.

Behavior

  • Best-effort delivery. We don't queue or retry — design your receiver to be idempotent.
  • 6-second timeout per delivery. Slow receivers are recorded as failed and we move on.
  • The last HTTP status and error per endpoint are visible in the admin panel.

Payload

message_posted.json
{
  "event": "message_posted",
  "project_id": 123,
  "data": {
    "comment_id": 67890,
    "room_id": 12345,
    "channel": "12345",
    "username": "Jane Doe",
    "message": "Hi, my order shipped to the wrong address.",
    "is_admin": false,
    "mentions": []
  }
}

Verifying the signature

verify.ts
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: Buffer, headerSig: string, secret: string): boolean {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  return (
    expected.length === headerSig.length &&
    timingSafeEqual(Buffer.from(expected), Buffer.from(headerSig))
  );
}

Common patterns

Slack relay

Subscribe to message_posted; format and forward to a Slack incoming-webhook.

CRM sync

On message_posted, log the message against the conversation in your CRM — room_id is a stable key.

Mention alerts

On mention_received, page the on-call lead so an at-risk conversation gets picked up fast.

Server

REST API

For deploy platforms and scripts that give each app its own chat: create a site per app, keep its allowed domains in sync with the app's hosts, read how its inbox is doing, show visitors a notice while the app is in maintenance or down, and record where it runs.

Authentication

Authorization: Bearer hbmcp_… — a token from Settings → AI agents (or an OAuth access token, as for the MCP server). It acts as the account owner and reaches that account's sites only: another account's id is a 404. Revoke it in the same place; changing your password revokes every token.

Conventions

  • JSON in and out: { data } on success, { error } (sometimes with a code) on failure. Bodies are JSON objects up to 64 KB.
  • 120 reads and 60 writes a minute per token; past that, 429 with Retry-After.
  • domains are host names (each covers its subdomains); URLs, ports and *. prefixes are reduced to the host. Up to 20.
  • A site's installedAt / lastSeenAt say when a page first and last loaded its snippet; lastVisitorAt, when a visitor last had the chat open. installState.state is installed, not_detected or shopify (installed through the Shopify app), as the MCP tools get_install and check_install say it.
  • installInstructions (one site's answers, not the list) is the text to paste into Claude Code, Cursor or Codex: where the snippet goes for each stack, the rules, how to check it, and how to connect the MCP server to finish the setup — the same text as Settings → Install → “Ask your AI agent”. For a site other than the account's first, it names the site and has the agent pass site to the MCP tools.
  • A notice past its until is simply no longer shown. Deploy links follow the same contract as Jentry's, one per app by key.
EndpointBodyWhat it does
GET /api/v1/projects—Your sites (projects), oldest first, without installInstructions.
POST /api/v1/projects{ name, domains? }Finds your site with that name (any case) or creates one: 201 { data, created: true }, or 200 { data, created: false } when it already existed (returned unchanged). At most 50 sites per account (403, code project_limit).
GET /api/v1/projects/:id—One site, with the installInstructions to give a coding agent.
PATCH /api/v1/projects/:id{ name?, domains? }Rename it (409, code name_taken, if another site has that name) or replace the hosts where its chat may load ([] = anywhere).
GET /api/v1/projects/:id/stats—open, unread, waiting, slaBreached, oldestWaitingAt; on plans with analytics also csat7d, csatCount7d and medianFirstReplySeconds7d (else null).
GET /api/v1/projects/:id/notice—The notice visitors see now, or null.
PUT /api/v1/projects/:id/notice{ text, until?, source? }Show visitors a notice above the conversation until `until` (ISO 8601, optional) or until removed. Plain text, 280 characters.
DELETE /api/v1/projects/:id/notice—Remove it: { data: { removed } }.
GET /api/v1/projects/:id/deploy-links—Where the site's code runs.
PUT /api/v1/projects/:id/deploy-links{ key, provider, instance, app, appUrl?, consoleUrl? }Add or replace (by key) one app's link. http(s) URLs only; 20 links at most.
DELETE /api/v1/projects/:id/deploy-links?key=…—Drop one: { data: { removed } }.
terminal
curl -X POST https://helpbird.app/api/v1/projects \
  -H "Authorization: Bearer hbmcp_..." \
  -H "Content-Type: application/json" \
  -d '{"name": "acme-shop", "domains": ["acme-shop.example.app", "shop.acme.com"]}'

# 201
{
  "data": {
    "id": 123,
    "name": "acme-shop",
    "domains": ["acme-shop.example.app", "shop.acme.com"],
    "active": true,
    "inactiveReason": null,
    "platform": "web",
    "embedUrl": "https://helpbird.app/api/embed?id=123",
    "snippet": "<script async src=\"https://helpbird.app/api/embed?id=123\"></script>",
    "panelUrl": "https://helpbird.app/settings?project=123",
    "inboxUrl": "https://helpbird.app/inbox?project=123",
    "installedAt": null,
    "lastSeenAt": null,
    "lastVisitorAt": null,
    "installState": {
      "state": "not_detected",
      "detail": "No page has loaded the snippet yet. It is detected the first time a page with it opens."
    },
    "installInstructions": "Install the HelpBird chat widget on this website: my HelpBird site \"acme-shop\" (project 123), …",
    "notice": null,
    "deployLinks": [],
    "createdAt": "2026-10-21T14:00:00.000Z"
  },
  "created": true
}
AI agents

MCP server

Claude, ChatGPT, Claude Code, Cursor and any other MCP client can do everything you do in the admin panel: read and answer conversations, assign, tag, merge and close them, keep contacts, saved replies and help-center articles up to date, run automations and campaigns, and change the widget's settings, the team and the plan. They act as the account owner, through the same checks as the admin panel. Start with the diagnose_account tool: what needs attention now, with the call that fixes each thing. Prompts clear_inbox, improve_bot and setup_workspace run whole jobs.

Server

https://helpbird.app/mcp — Streamable HTTP (stateless JSON-RPC). It signs in with OAuth 2.1: the first time, your client opens a HelpBird page where you sign in and click Allow. Nothing to register with Anthropic or OpenAI. Discovery at /.well-known/oauth-protected-resource/mcp, dynamic client registration, PKCE S256; redirects to https, http loopback or Cursor's app callback.

Connect

  • claude.ai: Settings → Connectors → Add custom connector, paste the URL.
  • ChatGPT: Settings → Apps & Connectors → Advanced settings → Developer mode → Create, paste the URL, OAuth.
  • Cursor, VS Code, Windsurf, Codex: add an HTTP MCP server with the URL.

Step-by-step for each client, what an agent can do, and the safety model →

Access

  • Only the account owner can connect apps. See and revoke them in Settings → AI agents; changing your password disconnects every app.
  • Plan limits apply exactly as in the panel. Tools that reach your customers (a reply, a file, a transcript, a campaign), delete something, send data or access outside your account (webhooks, alert addresses, new teammates, the identity secret) or cancel your plan return a preview and change nothing until called again with confirm: true; cancelling also needs the price echoed back (amount_confirmed).
  • No tool moves money: change_plan returns the link where you change the plan yourself (your Billing page, or Shopify's approval page).
  • Signing in, passwords, agent tokens, payment cards and deleting the account stay in the panel.

Claude Code

terminal
claude mcp add --transport http helpbird https://helpbird.app/mcp
# then, inside Claude Code:
/mcp
terminal
# Clients that can't sign in with OAuth: a token from Settings → AI agents
claude mcp add --transport http helpbird https://helpbird.app/mcp \
  --header "Authorization: Bearer hbmcp_..."
AI agents

Panel API

The JSON API behind the admin panel, as the MCP server's panel_api_read, panel_api_create, panel_api_update and panel_api_delete tools reach it, acting as the account owner. These are the only endpoints they accept; each runs the panel's own checks. Writes are previewed until called with confirm: true. Sign-in, passwords, agent tokens, the identity secret, billing changes and uploads are not part of it (they have their own tools, or stay in the panel); no endpoint that pays, bills a card or pays anything back is reachable.

Read (GET) — panel_api_read

Changes nothing. Parameters go in the query string.

EndpointWhat it doesQuery
GET /api/inbox/listConversations, most urgent first (one page).status=open|closed, q, assignee=mine|unassigned|owner:<id>|subadmin:<id>, unread=1, snoozed=1, tag=<tag id>, sla=breached, project=<site id>, cursor=<id>
GET /api/inbox/agentsThe owner and the teammates, with presence.—
GET /api/inbox/tagsConversation tags; with room_id, also the ones on that conversation.room_id
GET /api/inbox/savedviewsSaved inbox views.—
GET /api/inbox/cannedresponsesSaved replies (the first 100, most used first).—
GET /api/inbox/availabilityThe owner's availability.—
GET /api/inbox/notificationsThe owner's mention notifications.—
GET /api/settings/allEvery widget setting, the themes, blocked conversations and webhooks.—
GET /api/settings/webhooksOutgoing webhooks and their last delivery.—
GET /api/settings/blockedBlocked conversations.—
GET /api/account/overviewProfile, plan, seat limit and teammates.—
GET /api/account/teammatesTeammates.—
GET /api/account/invoicesRecent invoices (Stripe).—
GET /api/automations/listAutomation rules, tag names and assignable agents.—
GET /api/campaigns/listCampaigns and the contact tags they can target.—
GET /api/helpcenter/categoriesHelp-center categories.—
GET /api/helpcenter/articlesHelp-center articles and searches without results; with id, one article.id
GET /api/analyticsSupport analytics (Pro plan).days=7|30|90
GET /api/billing/getplanThe plan and subscription status.—
GET /api/shopify/embed-statusWhether the Shopify theme's HelpBird app embed is on.—

Create (POST) — panel_api_create

Makes something new. JSON body.

EndpointWhat it doesBody
POST /api/inbox/messageSend a reply to the customer, as the owner.room_id, message
POST /api/inbox/noteAdd an internal note (@Name mentions a teammate).room_id, message
POST /api/inbox/tagsCreate a conversation tag.action=create, name
POST /api/inbox/savedviewsSave an inbox view (overwrites one with the same name).action=create, name, query (the inbox query string)
POST /api/inbox/cannedresponsesCreate a saved reply.action=create, title, body, also_close
POST /api/settings/theme_saveCreate a color theme.without edit_theme_id; name, header_background_color, header_font_color, messages_color, font_color, border_color, background_color, chat_color, border_width
POST /api/settings/webhook_saveAdd an outgoing webhook (its signing secret is hidden in the answer).without id; url, events (comma-separated), active
POST /api/account/teammateAdd a teammate.without id; email, nickname, password
POST /api/automations/createCreate an automation rule.name, trigger, match=all|any, conditions[], actions[], stop_after, timeout_minutes
POST /api/campaigns/createDraft a campaign.title, body, target_tag
POST /api/campaigns/sendBroadcast a drafted campaign to its contacts, once.id
POST /api/helpcenter/categoriesCreate a help-center category.action=create, name
POST /api/helpcenter/articlesCreate a help-center article.action=create, title, excerpt, body, category_id, published

Update (POST) — panel_api_update

Changes something that exists. JSON body.

EndpointWhat it doesBody
POST /api/inbox/notifications_readMark notifications read (all, or the ids given).ids[]
POST /api/inbox/statusClose or reopen a conversation.room_id, status=open|closed
POST /api/inbox/prioritySet a conversation's priority.room_id, priority=0|1|2
POST /api/inbox/snoozeSnooze a conversation, or wake it (minutes=0).room_id, minutes, until_reply
POST /api/inbox/blockBlock or unblock a conversation.room_id, blocked=1|0
POST /api/inbox/banipAdd an IP to the banned list.room_id, ip
POST /api/inbox/bulkClose, reopen or snooze many conversations.room_ids[], action=close|open|snooze, minutes
POST /api/inbox/assignAssign a conversation.room_id, kind=owner|subadmin|none, agent_id
POST /api/inbox/tagsPut a tag on a conversation.action=apply, tag_id, room_id
POST /api/inbox/tagsTake a tag off a conversation.action=remove, tag_id, room_id
POST /api/inbox/contactnoteReplace the note of a conversation's contact.room_id, note
POST /api/inbox/contactattributeSet or remove an attribute of a conversation's contact.room_id, action=set|delete, key, value
POST /api/inbox/contacttagAdd or remove a tag of a conversation's contact.room_id, action=add|remove, name
POST /api/inbox/availabilitySet the owner's availability.status=active|away|busy|offline
POST /api/settings/saveGeneral, localization, behavior and appearance fields.id, name, restricted_domain, support_agent_name, language, … (see get_settings)
POST /api/settings/hoursBusiness hours and the away message.business_hours_enabled, business_days, business_open, business_close, business_timezone, away_message
POST /api/settings/greetingThe greeting.default_message, default_message_delay
POST /api/settings/proactiveThe proactive message.welcome_bot_enabled, welcome_message, welcome_delay_seconds, welcome_url_contains, welcome_followup_message, welcome_followup_delay_seconds
POST /api/settings/aiAI auto-reply.ai_autoreply_enabled, ai_autoreply_prompt, ai_autoreply_daily_cap, ai_summary_on_close
POST /api/settings/routingAuto-assignment and the first-response SLA.auto_assign_enabled, sla_response_minutes
POST /api/settings/moderationBanned words and IPs, AI moderation, slow mode.banned_words, banned_ips, enable_ai_moderation, slow_mode_seconds
POST /api/settings/notificationsThe email digest.email_notification, email_notification_time, email_notification_account
POST /api/settings/alertsNew-conversation alerts (email, Slack).support_email_alerts, support_alert_emails, slack_webhook_url
POST /api/settings/theme_saveChange one of the account's themes.with edit_theme_id; edit_theme_id, name, colors…
POST /api/settings/webhook_saveChange a webhook.with id; id, url, events, active
POST /api/settings/blockUnblock (or block) a conversation from Moderation.room_id, blocked
POST /api/account/profileThe owner's display name, avatar and link (not the login email).nickname, image, profile_link
POST /api/account/teammateChange a teammate's name, email or password.with id; id, email, nickname, password
POST /api/account/teammate-loginLet teammates sign in to the panel, or not.enabled
POST /api/automations/updateChange an automation rule.id, name, trigger, match, conditions[], actions[], stop_after, timeout_minutes
POST /api/automations/toggleSwitch a rule on or off.id
POST /api/automations/reorderSet the order rules run in.order[] (rule ids)
POST /api/helpcenter/categoriesRename or reorder a category.action=update, id, name, position
POST /api/helpcenter/articlesChange an article.action=update, id, title, excerpt, body, category_id, published
POST /api/setup/skipMark a getting-started step skipped.step=install|customize|welcome|hours|team

Delete (POST) — panel_api_delete

Removes something for good. JSON body.

EndpointWhat it doesBody
POST /api/inbox/mergeMerge a conversation into another; the source goes away.source_room_id, target_room_id
POST /api/inbox/tagsDelete a conversation tag everywhere.action=delete, tag_id
POST /api/inbox/savedviewsDelete a saved view.action=delete, id
POST /api/inbox/cannedresponsesDelete a saved reply.action=delete, id
POST /api/settings/theme_deleteDelete one of the account's themes.theme_id
POST /api/settings/webhook_deleteDelete a webhook.id, project_id
POST /api/account/teammate-deleteRemove a teammate.id
POST /api/automations/deleteDelete an automation rule.id
POST /api/campaigns/deleteDelete a campaign.id
POST /api/helpcenter/categoriesDelete a category (its articles stay).action=delete, id
POST /api/helpcenter/articlesDelete an article.action=delete, id