Guides
Send a WhatsApp message from Node.js
HelloHop lets you send a WhatsApp text from Node.js with a POST request to your linked channel. Send the recipient and text as JSON, authenticated with the channel token. A successful response means WhatsApp accepted the message on its servers. Delivery and read receipts arrive separately through signed webhooks.
Facts (as of October 2026, API v1)
- Text sends use POST /v1/sessions/{channel}/messages/text with to and text.
- A successful send returns id, chat_jid, timestamp and status: server_ack.
- There is no API idempotency key. A send_unconfirmed response does not prove the message failed.
Steps
- Get a channel token. Use the console to link a number and create its channel token. Set CHANNEL_ID and CHANNEL_TOKEN in your environment.
- Choose a recipient. Replace 66XXXXXXXXX with a phone number in full international form, digits only, or use a WhatsApp JID.
- Send once. Run the Node.js example below. Keep the returned message id for matching later message.status webhooks.
- Receive status updates. Configure a webhook receiver subscribed to message.status, and verify its signature before accepting events.
Send text with Node.js
Use a Node.js runtime with built-in fetch. Save this as send.mjs and run node send.mjs so top-level await is supported. The example throws on a non-success response.
const API = 'https://api.hellohop.app/v1';
const { CHANNEL_ID, CHANNEL_TOKEN } = process.env;
const BASE = `${API}/sessions/${CHANNEL_ID}`;
const headers = {
Authorization: `Bearer ${CHANNEL_TOKEN}`,
'Content-Type': 'application/json',
};
async function call(method, path, body) {
const res = await fetch(`${BASE}${path}`, {
method,
headers,
body: body === undefined ? undefined : JSON.stringify(body),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.code}: ${data.error}`);
return data;
}
const sent = await call('POST', `/messages/text`, {"to":"66XXXXXXXXX","text":"Thanks, see you tomorrow"});
console.log(sent);Read the response correctly
A 200 response with status: server_ack means WhatsApp servers accepted the message. It does not prove delivery to the phone. Keep id and subscribe to message.status for delivered and read updates. An API send is not echoed as a message webhook.
Handle errors before retrying
| Response | Next step |
|---|---|
| 401 unauthorized | Check the channel ID and token. |
| 409 not_linked | Link the number in the console. |
| 429 sandbox_allowance_exceeded | Wait until resets_at. |
| 429 rate_limited or gateway_busy | Retry only after Retry-After; these are pre-send refusals. |
| 504 send_unconfirmed or a lost response | Record possibly delivered. Do not resend automatically. |
These examples send once and have no retry loop. If a response is lost or a send is unconfirmed, confirm with the recipient where possible before sending again. Other 500, 502 and 503 write errors can also follow an applied operation.
Questions
- Can I start in the free sandbox?
- Yes. Use the token of your sandbox channel and link a WhatsApp number. Sandbox allowances apply; an exhausted allowance returns sandbox_allowance_exceeded.
- What goes in to?
- A recipient phone number with country code, in digits only, or a WhatsApp JID. Replace the example placeholder before sending.
- Does server_ack mean delivered?
- It means WhatsApp servers accepted the message. Delivery and read status arrive later as message.status webhooks.
- Is it safe to retry a timeout?
- A timeout or lost response can leave the message possibly delivered. There is no API idempotency key. Do not resend automatically.
Free sandbox, forever. Add a real number when you're ready.
Start in the free sandboxKeep going
HelloHop is an independent WhatsApp API for developers: send and receive messages, automate groups and communities, and get signed webhooks with a free sandbox. Not affiliated with WhatsApp or Meta. You link your own number.