You keep your app; HelloMe runs the messaging behind it. Your server creates your users, opens and closes conversations and hands your app a short session. Your app shows the conversations, sends and receives in real time, and places calls.
Nothing is tied to one trade. A user, a conversation, a free role, a reference and free fields: a mobility platform, a clinic, a school, a shop or a full messenger all use the same building blocks.
Your users stay yours. They appear nowhere in HelloMe, cannot write to anyone outside your conversations, and we never use their data for anything but your service.
1.API reference
The complete reference of every route, with a playground to try it with your key: hello-me.net/developers/api.
2.How it fits together
Your app ──(short session)──► HelloMe API: conversations, messages, files, calls, realtime
▲
│ session
Your server ──(server key hm_sk_…)──► HelloMe API /platform: users, conversations, sessions
▲
└────────── signed webhooks: message, call, closing, report- The server key never leaves your server. It carries the `messaging` scope and opens your workspace only.
- A session is handed to your app for one person and one device; it expires (24 h by default, configurable) and can be revoked instantly.
- Webhooks tell your server what happens, so your own logic can react.
3.In ten minutes
In the HelloMe console, open your workspace, Integrations tab, and create a key with “For my app’s messaging” ticked. Then, from your server:
curl -X PUT https://api.hello-me.net/api/v1/platform/users/customer-4521 \
-H "X-HelloMe-Key: hm_sk_…" -H "content-type: application/json" \
-d '{"name":"Amina Kossi","role":"customer"}'
curl -X PUT https://api.hello-me.net/api/v1/platform/users/agent-77 \
-H "X-HelloMe-Key: hm_sk_…" -H "content-type: application/json" \
-d '{"name":"Kofi","role":"agent"}'curl -X POST https://api.hello-me.net/api/v1/platform/conversations \
-H "X-HelloMe-Key: hm_sk_…" -H "Idempotency-Key: $(uuidgen)" -H "content-type: application/json" \
-d '{"ref":"case-42","title":"Case 42","participants":[{"externalId":"customer-4521"},{"externalId":"agent-77"}],"metadata":{"branch":"Lomé"}}'curl -X POST https://api.hello-me.net/api/v1/platform/users/customer-4521/sessions \
-H "X-HelloMe-Key: hm_sk_…" -H "content-type: application/json" \
-d '{"deviceId":"install-abc","platform":"android","pushKey":"<FCM token>"}'
# → {"accessToken":"…","expiresAt":"…"}The app sends this token as `Authorization: Bearer …` on the messaging routes (`GET /channel`, `POST /channel/{roomId}/message`…) and as the `auth` query on the realtime socket. The `roomId` is the one of the conversation created.
4.The JavaScript SDK
`@hellome/platform` holds three things: the server client, the app client and webhook verification. It retries a lost request (network, 429, 5xx) by itself with the same idempotency key, so a retry never acts twice.
import {HelloMeServer} from "@hellome/platform/server";
const hm = new HelloMeServer({key: process.env.HELLOME_KEY!});
await hm.users.upsert("customer-4521", {name: "Amina Kossi"});
const conv = await hm.conversations.create({
ref: "case-42", title: "Case 42",
participants: [{externalId: "customer-4521"}, {externalId: "agent-77"}],
});
const {accessToken} = await hm.sessions.create("customer-4521", {deviceId: "install-abc"});
await hm.conversations.close(conv.id, "Case closed, thank you!");import {HelloMeClient} from "@hellome/platform/client";
import {io} from "socket.io-client";
const chat = new HelloMeClient({
// your server, which calls sessions.create
getSession: () => fetch("/api/chat-session").then((r) => r.json()).then((r) => r.accessToken),
});
const socket = await chat.realtime(io);
socket.on("v1OnNewMessage", (raw: string) => show(JSON.parse(raw)));
await chat.sendText(roomId, "Hello!");
await chat.sendFile(roomId, photo, {type: "image", name: "photo.jpg"});An expired or revoked session is asked again from your server once, without the user noticing. The app client refuses to run with a server key: it has no place in an app.
5.Conversations
| Action | Route |
|---|---|
| Open (same `ref` = same conversation) | POST /platform/conversations |
| List and filter (`status`, `ref`, `participant`, `metadata.<key>`) | GET /platform/conversations |
| Change title, picture, fields, scheduled closing, settings | PATCH /platform/conversations/{id} |
| Add / remove a participant | POST …/participants · DELETE …/participants/{externalId} |
| Write as your company or as a participant | POST …/messages |
| Export every message | GET …/messages |
| Close (read only), reopen, archive | POST …/close · …/reopen · …/archive |
| Bring in your support | POST …/support |
A closed conversation stays readable; nobody writes or calls in it any more. `closeAt` closes it by itself at the chosen moment. Per conversation, you allow calls and files or not; the largest file size is set for the whole workspace.
Support: your agents are members of your HelloMe workspace. `POST …/support` brings in the least busy available agent (or one of a team), who answers from their HelloMe app. Customer ↔ support, staff ↔ support and customer ↔ staff all go through one system.
6.Building a full messenger
With `directory: true` (`PATCH /platform/config`), your users can find each other (`GET /platform-app/people`) and open a conversation themselves (`POST /platform-app/conversations`) — always inside your workspace, never with anyone else.
7.Notifications
Your notifications leave with your own keys: your Firebase project (`PUT /platform/config/push/fcm`, the service account JSON) and your Apple `.p8` key for incoming calls on iPhone (`PUT /platform/config/push/apns`). They never go through HelloMe’s project.
The device token is given when the session is created (`pushKey`, `voipKey`) or from the app (`POST /profile/push`). Without keys, nothing is sent: the `platform.message.created` webhook lets you notify by yourself.
8.Webhooks
Declare an https address in the console. Events: `platform.message.created`, `platform.conversation.opened`, `.closed`, `.archived`, `platform.participant.added`, `.removed`, `platform.call.started`, `.ended` (duration and minutes), `platform.report.created`.
import {parseWebhook} from "@hellome/platform/webhooks";
app.post("/hellome", express.raw({type: "application/json"}), (req, res) => {
const event = parseWebhook(process.env.HELLOME_WEBHOOK_SECRET!, req.header("x-hellome-signature")!, req.body);
// event.event, event.data …
res.sendStatus(200);
});Every delivery is signed (HMAC-SHA256 of `timestamp.body`) and timestamped: a forged delivery, or one replayed more than five minutes later, is refused. A failed delivery is sent again after 2 s and 10 s; after 20 failures in a row the address is put to sleep rather than hammered.
9.Test environment
Create a test key (console → Integrations → “Test key”): it starts with `hm_sk_test_` and reaches only a twin of your workspace, with its own users, conversations, settings and webhooks. Nothing there is billed and nothing there touches your real data: a test key gets 404 on everything live, and the other way round.
- Every answer carries the `x-hellome-environment: test` or `live` header.
- Open on every plan, so you integrate before you pay; 50 active users a month at most.
- One-time codes are not sent from a test key (`403 test_key_not_allowed_here`): a test never sends a real SMS.
- In the console, the Live / Test switch shows one or the other, never both mixed.
10.The voice
When HelloMe opened them, three voice features come with ElevenLabs’ voice:
- Voice message: `POST /platform/conversations/{id}/voice-messages` with `{text, from?}` — your text, spoken and sent as a voice note (its words stay on the message). Paid from your credit, per 1,000 characters.
- Hear a message, and hear a voice note in another language: `POST /voice/messages/{roomId}/{messageId}/read-aloud` (answers `audio/mpeg`) and `…/translate` with `{to}`, called by your app with its session.
- Voice agent: turn it on in your console (Platform → Settings); your app then calls `POST /voice/agent/session` with its session, gets a `conversationToken` and runs `Conversation.startSession({conversationToken, connectionType: "webrtc"})` from `@elevenlabs/client`; at the end, `POST /voice/agent/session/{id}/end` with the conversation id. Minutes are taken from your credit.
- Never an encrypted, deleted or view-once message, nor a conversation under advanced privacy. `app-config` says what is open: `features.readAloud`, `features.voiceTranslate`, `features.voiceAgent`, `voice.languages`.
11.Billing beyond the plan
Your plan includes a number of active users a month (at least one session or one message). Beyond it:
- If your plan has a price per extra user, it is taken from your HelloMe credit at each new person’s first session of the month. Short credit: that new session is refused (`402 insufficient_credit`); people already active and conversations going on continue.
- Without that price, the ceiling is firm: `403 plan_platform_users_reached` for a new person.
- Call minutes, when your plan prices them, are taken after the call: a call is never cut for credit.
- The test environment is never billed.
- The console shows your prices, your credit and the month’s usage.
12.Security: what we guarantee
- Server keys are never stored: only their SHA-256 fingerprint is kept. A lost key is replaced, not recovered.
- Push keys are sealed with AES-256-GCM before they are stored, and never sent back by the API.
- Strict isolation: a user of your app reaches only the messaging routes they need; every other route answers 403. They are absent from every HelloMe search, and their phone and e-mail are kept apart — never used for a HelloMe sign-in, never taken as verified.
- Workspaces are sealed from each other: a key sees its own workspace only. Any resource of another workspace answers 404; our end-to-end tests check it.
- Short sessions, bound to one device, revocable at once (`DELETE …/sessions`).
- Webhooks over https only, signed, never following a redirect, and never to an internal address: the address is checked when declared and again at every connection.
- Every input is validated: identifiers, free fields (4 KB, keys without operators), https pictures only.
- Every change of settings, keys or sessions is written to your workspace’s audit trail.
- Encryption in transit (TLS) between your app, your server and HelloMe. Messages are not end-to-end encrypted: that is what makes the export, the retention you set and your support’s access possible.
13.Reliability
- Idempotency: every creation accepts `Idempotency-Key`. The same request sent again gets the first answer; two simultaneous copies cannot both act.
- The same `ref` always gives the same conversation, even when two calls arrive together.
- Stateless API: any copy of the API answers; realtime, locks and limits are shared.
- A slow server of yours never slows a message: webhooks, notifications and meters run in the background.
- Scheduled jobs (scheduled closings, retention) run once, even with several copies.
- Rate limit per company (`x-ratelimit-*` headers, `Retry-After`): another company in a loop does not slow you down.
- Versioned API (`/api/v1`): a breaking change is announced in advance, never imposed.
14.Your data
You remain responsible for your users’ data; HelloMe processes it on your behalf and for nothing else. Export it at any time (`GET …/messages`), set how long it is kept (`retentionDays`) and close a user when they ask (`DELETE /platform/users/{externalId}`).
15.Errors and limits
| Code | Meaning |
|---|---|
| 401 server_key_invalid | Key missing, wrong or revoked |
| 403 scope_required:messaging | The key lacks the messaging scope |
| 403 plan_no_platform | Your plan does not include the platform |
| 402 insufficient_credit | Not enough credit for a user beyond the plan |
| 403 plan_platform_users_reached | Monthly active user ceiling reached (conversations going on continue) |
| 403 platform_conversation_closed | Closed conversation: read only |
| 403 platform_session_not_allowed | An app session on a route not open to it |
| 404 platform_user_not_found / platform_conversation_not_found | Unknown in your workspace |
| 409 platform_request_in_progress | The same Idempotency-Key is in progress: retry in a moment |
| 413 platform_file_too_large:<n>MB | Beyond the size your workspace set |
| 429 platform_rate_limited | Too many calls this minute; see Retry-After |