You paste one line into your site: a button appears, your customers write, your team answers from the HelloMe app they already have. This guide covers installation, verified identity, the server API and webhooks.
Everything below runs on two things: the widget public key, which lives in your page, and a server key, which must never leave your server.
1.API reference
The complete reference of every route, with a playground to try it with your key: hello-me.net/developers/api.
2.In five minutes
- Create your workspace in HelloMe: Support → new workspace. You own it.
- Copy the widget public key (it starts with "hm_") from the workspace settings.
- Add your site's domain to the list of allowed domains: without it, the window refuses to open anywhere but on your site.
- Paste the line below just before the closing body tag.
<script
src="https://hello-me.net/livechat.js"
data-key="hm_your_public_key"
defer
></script>Nothing else loads until someone clicks: your page pays six compressed kilobytes and does not move by a pixel.
Then invite your agents by phone number, from the Support screen. Each of them accepts from their own HelloMe account: there is no company password to share.
3.Configuring the window
The script takes a few attributes. Everything else — color, greeting, the questions you ask — is set in HelloMe and applies without touching your page.
| Attribute | What it does | Default |
|---|---|---|
| data-key | Your workspace public key. Required. | — |
| data-side | The corner the button starts in: "right" or "left". | right |
| data-color | The button color, if you do not want the workspace one. | the workspace color |
| data-locale | The language of the window. | the browser language |
| data-label | The text screen readers announce on the button. | "Open the chat" |
Visitors can move the button, with a finger or the mouse, when it covers something they need: it stays where they put it, anywhere on the screen, and the window opens beside it. The spot is kept for their visit in that tab; on the next visit the button is back in its corner.
From your own code, the window opens, closes and can be listened to:
// Open from your own button
document.querySelector("#help").addEventListener("click", () => {
HelloMeChat.open();
});
// Know when a message arrives
HelloMeChat.on("message", (message) => {
console.log("New message:", message.content);
});
HelloMeChat.close();
HelloMeChat.toggle();
HelloMeChat.destroy(); // removes everything from the page4.Telling us who your customer is (verified identity)
By default, whatever the visitor types in the window is marked "claimed": your agent sees it, but nothing proves it. If your customer is already signed in on your site, you can vouch for them — the agent then sees a trusted identity.
How it works: your server signs your customer's id with your workspace secret, and your page passes that signature along. The secret never leaves your server.
import { createHmac } from "crypto";
const secret = process.env.HELLOME_WIDGET_SECRET; // never in the page
const hash = createHmac("sha256", secret)
.update(String(customer.id))
.digest("hex");
// pass this to your template
res.render("page", { helloMe: { id: customer.id, name: customer.name, email: customer.email, hash } });<?php
$secret = getenv('HELLOME_WIDGET_SECRET');
$hash = hash_hmac('sha256', (string) $customer->id, $secret);HelloMeChat.identify({
id: "<?= $customer->id ?>",
name: "<?= $customer->name ?>",
email: "<?= $customer->email ?>",
phone: "<?= $customer->phone ?>",
// Anything you want the agent to know — 20 fields at most.
attributes: {
kyc: "<?= $customer->kycStatus ?>",
customerNumber: "<?= $customer->number ?>",
},
hash: "<?= $hash ?>",
});Only the id is signed: it is what stops anybody from passing as another of your customers. The rest travels with the verified identity; share only what you are happy for your agents to see. The customer is never asked again, and is recognised on their next visit, on any device, with their whole history.
Never compute this signature in the browser: that would publish your secret, and anyone could impersonate any of your customers.
5.Server keys
A server key lets your software call the API: read your conversations, write on behalf of your company, close what is settled. An admin creates it in the workspace, and it is shown only once.
- The "read" scope: read conversations and messages.
- The "write" scope: write to the customer, tag, close.
- A lost key cannot be recovered: revoke it and create a new one. That is also what to do the day it leaks.
curl https://api.hello-me.net/api/v1/livechat/api/conversations \
-H "X-HelloMe-Key: hm_sk_your_server_key"A server key must never appear in a page, in a mobile app, or in a code repository. It lives on your server, in your environment variables.
6.The API
Every URL starts with https://api.hello-me.net/api/v1/livechat/api and answers in JSON, wrapped in { code, data, msg }. The key decides the company: a conversation that is not yours answers exactly like a conversation that does not exist.
| Method and path | What it does | Scope |
|---|---|---|
| GET /conversations | List your conversations, most active first. Filters: status, page, limit. | read |
| GET /conversations/{id} | One conversation and its last hundred messages, with who wrote what. | read |
| POST /conversations/{id}/messages | Write to the customer on behalf of your company. | write |
| PATCH /conversations/{id} | Close a conversation, put it back in the queue, tag it. | write |
| GET /agents | How many agents are on duty right now. | read |
| POST /conversations/{id}/call | Start an audio call, or a video one with withVideo. Returns the key to join it. | write |
| POST /conversations/{id}/call/end | Hang up, and count the minutes used. | write |
curl -X POST \
https://api.hello-me.net/api/v1/livechat/api/conversations/CONVERSATION_ID/messages \
-H "X-HelloMe-Key: hm_sk_your_server_key" \
-H "content-type: application/json" \
-d '{
"content": "Your order #45321 is ready, you can come and pick it up.",
"idempotencyKey": "order-45321-ready"
}'"idempotencyKey" is your own id for this message. If your call fails and you replay it, the message is written only once: that is what makes a retry safe.
A message sent through the API shows up in the customer's window under your company name, and in your agents' app like any other message.
7.Webhooks
Rather than polling the API in a loop, let us tell you. Declare an https URL in your workspace, pick the events, and keep the secret you are given only once.
| Event | When |
|---|---|
| conversation.opened | A visitor opens a conversation. |
| message.from_visitor | The customer writes. |
| message.from_agent | An agent replies. |
| conversation.assigned | An agent takes the conversation. |
| conversation.resolved | The conversation is closed. |
| call.started | A call starts in the conversation. |
{
"event": "message.from_visitor",
"at": "2026-09-18T17:31:02.000Z",
"workspaceId": "66f1c2a9e4b0a1b2c3d4e5f6",
"data": {
"conversationId": "66f1c2a9e4b0a1b2c3d4e600",
"message": { "id": "…", "content": "Hi, has my order shipped?", "at": "…" },
"visitor": { "name": "Ama Mensah", "email": "ama@example.com", "phone": "+228…", "identity": "claimed" }
}
}Every delivery is signed. Verify the signature before you do anything with the payload: that is what tells our call apart from anyone else's.
import { createHmac, timingSafeEqual } from "crypto";
export function isAuthenticDelivery(header, rawBody, secret) {
const parts = Object.fromEntries(
header.split(",").map((piece) => piece.trim().split("=")),
);
const timestamp = Number(parts.t);
// A delivery older than five minutes is rejected: that shuts the door on
// replaying an old call.
if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const received = String(parts.v1 || "");
if (received.length !== expected.length) return false;
return timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}- The header is called "X-HelloMe-Signature" and reads "t=…,v1=…".
- Sign over the raw body, before any JSON parsing: a re-encoded object does not produce the same signature.
- Answer 2xx quickly. We retry three times, then we give up on that delivery.
- A URL that fails twenty times in a row is put to sleep, so we do not flood you when your server comes back.
8.Limits and errors
| Code | What it means | What to do |
|---|---|---|
| 401 server_key_invalid | The key is unknown or revoked. | Check the header, or create a new key. |
| 403 scope_required:write | The key is read-only. | Create a key with the "write" scope. |
| 404 conversation_not_found | The conversation does not exist, or is not yours. | Check the id. |
| 400 conversation_closed | The conversation is closed. | Reopen it with PATCH, or write elsewhere. |
| 403 origin_not_allowed | The window was opened from a domain that is not allowed. | Add the domain in the workspace. |
| 403 identity_signature_invalid | The identity signature does not match. | Check the secret and what you sign. |
| 429 | Too many calls. | Slow down, retry later. |
- Opening the window: sixty per minute per IP address — enough for a whole office or cybercafé behind one connection.
- Site contact form: five per hour per IP address.
- Server API: the general API limits apply; write to us if your volume goes past them.
9.Trying it safely, and the Postman collection
Create a second workspace and leave it on the free plan: that is your sandbox. It has its own widget key, its own server keys, its own webhooks and no real conversations in it. Nothing you do there touches your real customers, and you can empty it whenever you like.
- Declare your staging site's domain there, or no domain at all while you are trying things: an empty list accepts anything, and the screen says so.
- Calls and the API need a paid plan: to try them, put your sandbox on Shop for the time of your tests, or test in your main workspace.
- A conversation opened in the sandbox counts against its own ceiling, not your main workspace's.
The Postman collection below holds every address, grouped by what opens it: the window, the visitor, your software, your agents. It is generated from the API's own description, so it cannot say anything other than what the server really does.
curl -O https://hello-me.net/livechat/hellome-livechat.postman_collection.jsonAfter importing it, fill in “baseUrl”, “widgetKey” and “serverKey”, then run “Open a session”: it gives you the visitor token the next requests expect.
10.Versions and deprecation
The API address carries its version: /api/v1/. As long as that number does not change, what works today will work tomorrow. We add fields and routes; we do not remove them and we do not change what they mean.
- A field may appear in a response at any time: your code should ignore what it does not know rather than fail on it.
- A route or a field only ever disappears with a change of version, never within one.
- A new value may appear in a closed list — an event type, a status: treat the unknown as “nothing to do”, not as an error.
- A webhook may gain new events; you only receive the ones you subscribed to.
The day a v2 exists, v1 stays served for twelve months after the announcement, and six months after the last request you sent to it — whichever is later. You will be told by e-mail at your workspace's address, and the date will be on this page.
Nothing is deprecated today. This page will say what, from when, and what replaces it, before anything stops working.
11.What your customers need to know
By installing the window, you ask us to process your customers' messages on your behalf. Two things are on you:
- Say in your own privacy policy that you use a chat service, and what it collects.
- Do not ask in the window for information you do not need — a card number has no business being there.
On our side: what the visitor types stays marked "claimed" until something proves it, no account is created in their name without verification, and the assistant never reads a chat placed under advanced privacy.
12.Try it before you open it to customers
- Create a second workspace, named "Test", with your staging domain.
- Open the window on that staging site and write: the conversation must show up in your agents' queue.
- Point a webhook at a tool that displays incoming requests, and verify the signature with the example above.
- Cut your connection mid-conversation: the message must stay on screen and send itself once the network is back.
A question this page does not answer: write to us from the contact page, and tell us your workspace name.