How it works
How it works, from signing up to answering a customer
Two things happen here and they are worth separating. Customers write to you on whichever channel they use, and somebody on your team answers them - that needs no code at all. And messages you would rather not type by hand go out on their own, which is where the integrations and the API come in. The four steps below cover both.
Start your trial
An email address and a password. Seven days, no card, and nothing is cut down: the trial is a Starter account with a clock on it.
Connect your channels
A WhatsApp number is a code you scan from the phone, exactly as you would link a laptop, and the console shows the connection live so you know it worked. A Facebook Page or an Instagram account is a Connect button and a list of the Pages you already run. Nothing asks you for a token or a webhook address.
Answer, from one place
Every conversation on every connected channel arrives in one list, marked with the channel it came from and sorted by whether anybody has dealt with it yet. Comments on your Facebook and Instagram posts have a screen beside it. Your colleagues each get their own login and a role, so somebody can answer customers without being able to touch your plan or your keys.
Automate whatever you would rather not type
Order updates, invoices, reminders. An integration does it if your shop runs on a platform we support, or one HTTP call does it if you would rather write it. Both send from the same number and land in the same conversation history.
Inbound
What happens when a customer writes to you
This is most of what Njiwa does.
It arrives in about a second
Whichever channel it came in on. A photograph is stored as a photograph, a PDF is readable in the conversation, a voice note plays where it landed.
Everyone who should see it, does
Every colleague with a login sees the conversation, unless you have restricted them to particular numbers, which fails closed. Nobody is passing a handset around and nobody is waiting for the person who has it.
A reply goes back out the way it came in
Type it and it returns on that channel, as your business. The customer sees your name and your number, not the name of whoever answered - unless you switch signatures on and decide they should.
And it is on the record
Every outgoing message keeps the name of whoever sent it, whether that was a person, one of your keys, or an auto-reply. So "who told the customer that" has an answer.
Saw your post about the drill sets
Hi Peter - the 18V set is in, 7,900.
Can I collect tomorrow morning?
Yes, we open at 8. I will set one aside.
Outbound
Where a message you send actually starts
Four ways, and most businesses never touch the second. A reply typed by a person in the inbox is the commonest of all and needs none of this; what follows is for the messages nobody should have to type.
Your shop runs on a platform we integrate with
Install the integration, paste your key, and tick the order statuses that should reach the customer. There is no code in this route at all. Nine platforms have one: WooCommerce, Shopify, Magento 2, PrestaShop, OpenCart, Shopware 6, Medusa, ERPNext and Frappe, and Odoo. Every event is off until you switch it on, so installing one sends nothing to anybody until you say so, and the wording of every message is yours to edit.
The software is your own
One POST to /v1/messages, from whatever you already write in. There is no SDK you are obliged to use: if your language can make an HTTP request, it can send a WhatsApp message. There are thin SDKs for PHP, Node and Python if you would rather not write the HTTP yourself. You get a message id back straight away, and the delivery updates arrive on your webhook as WhatsApp reports them.
Nothing happened, it is simply time
Appointment reminders, renewal notices, the delivery window on the morning it opens. No order changed state and no customer did anything: a job ran. It is the same call, fired from cron or whatever runs your scheduled work. Send an Idempotency-Key with it and a job that runs twice still sends once, which matters more here than anywhere else.
Somebody writes back
A message you send is the start of a conversation, not the end of one. Replies arrive at your endpoint within a second as message.received, signed the same way the delivery updates are. If you would rather not build an inbox, the console already is one: every contact is a single thread with both sides of what was said, oldest to newest, and you can answer straight from it.
curl -X POST https://njiwa.upeo.ai/v1/messages \
-H "Authorization: Bearer sk_live_your_key" \
-d '{"to": "0712345678", "text": "Your order has shipped"}'
{
"id": "msg_01J9ZK4Q7M2X8P0R3V6T5W1YHD",
"status": "sent",
"to": "254712345678",
"type": "text",
"created_at": "2026-08-31T09:14:02Z"
}
After the call returns
What happens to a message once we have it
The id comes back before the message has gone anywhere, and that is deliberate. Once Njiwa has answered with an id, sending it is our problem rather than yours.
- If the number is offline, the message waits for it. Nothing is thrown away for being early.
- If a send fails for a moment, it is retried with a widening gap. If we restart in the middle of one, it is picked back up.
- As WhatsApp reports it,
message.statusis posted to your endpoint: sent, then delivered, then read. - When somebody replies,
message.receivedarrives the same way, usually within a second. - Every delivery is signed with HMAC SHA-256 and timestamped, so your handler can prove the request came from us and a captured one cannot be replayed at you later.
- A message that genuinely cannot go is marked failed with a reason you can read, rather than left in a queue nobody is watching.
Send an Idempotency-Key and a repeat of the same request
returns the same message id instead of a second message, so a timeout on
your side stops being a decision about whether to risk sending twice.
WhatsApp only
Which WhatsApp rail you are on
Njiwa can put a message on WhatsApp by two roads, and they look identical from your code. The Web rail speaks the same multi-device protocol WhatsApp Web speaks: no approval, a number you already own, nothing per message from Meta, and about five minutes to the first message. The Cloud rail is Meta's official Business Cloud API: business verification, a dedicated number, and a charge per conversation.
It matters for more than billing. Outside a twenty four hour window opened by the customer, the Cloud rail only carries templates you got approved in advance. Every number in Njiwa is labelled with its rail, in the console and in the API, so you always know which one you are on.
What people send
The messages this ends up being
Invoices and receipts
Attach the PDF your system already generates and send it to the number on the order. It arrives in the same app the customer is already reading.
Delivery and order updates
Tell someone their order has shipped without paying per message for an SMS that may not be read.
Appointment reminders
Fire them from a cron job. Replies come back to your webhook, so a customer answering the reminder reaches a person.
Two way support
Incoming messages arrive at your endpoint within a second. Reply from your own system, or from the console, where each customer is a single thread showing both sides of what was said.
Start with the test key
Every account has two. The one beginning sk_test_ checks
every request, stores every message and fires real webhooks, and delivers
nothing to a phone. The one beginning sk_live_ sends for real,
to real people. Build against the test key, rehearse the whole thing, then
paste in the live key. Nothing else changes.