Messaging gateway API
One API for every messaging channel
Send WhatsApp Business, SMS, Telegram, Messenger, Instagram and TikTok messages through a single REST endpoint. Prepaid, billed per outbound message, with delivery webhooks and a test mode.
- From
- $0.0003
- per outbound message
- On signup
- 100
- free messages
- Commitment
- None
- prepaid, no contract
curl https://api.omnimessage.co/v1/messages \
-H "Authorization: Bearer om_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-shipped" \
-d '{
"channel": "ch_7Hq2mN5vB8cX1zL0pK3j",
"to": "+971501234567",
"type": "text",
"text": { "body": "Your order #1042 has shipped." },
"reference": "order-1042"
}'{
"id": "msg_2b1Xw9aQ3rT8yU0pL4kZ",
"object": "message",
"mode": "live",
"channel_id": "ch_7Hq2mN5vB8cX1zL0pK3j",
"channel_type": "whatsapp",
"direction": "outbound",
"to": "+971501234567",
"from": "+971800123456",
"type": "text",
"content": {
"text": { "body": "Your order #1042 has shipped." }
},
"status": "queued",
"error": null,
"reference": "order-1042",
"metadata": {},
"billing": {
"source": "wallet",
"amount_micros": 1000,
"package_grant_id": null,
"refunded": false
},
"created_at": "2026-10-05T09:30:00.000Z",
"sent_at": null,
"delivered_at": null,
"read_at": null,
"failed_at": null
}Channels
Seven channel types, one request shape
Connect the senders you already own. Each one becomes a channel ID that you pass to the same endpoint, and each reports the same statuses back.
- $0.001WhatsApp BusinessTemplates, interactive messages and media on your own Cloud API number.Text · Attachments · Template · Reply buttons · List · URL button · Location · Contacts
- $0.0005SMSText and media messages from your own Twilio number.Text · Attachments
- $0.0005SMS OTPA text-only route for one-time passcodes.Text
- $0.0003TelegramBot messages with buttons, polls, locations and media.Text · Attachments · Reply buttons · Location · Contacts · Poll
- $0.0005MessengerConversations with people who message your Facebook Page.Text · Attachments · Reply buttons
- $0.0005InstagramDirect messages for an Instagram professional account.Text · Attachments · Reply buttons
- $0.0005TikTokDirect messages for a TikTok business account.Text · Attachments · Reply buttons
- Bring your own channelYour numbers and bots stay yoursSee what each channel needs
How it works
From signup to a delivered message in four steps
There is no sales call and no minimum commitment. You can make your first API call in test mode a minute after creating an account.
- Step 01
Create an account
Sign up, verify your email and create an API key in the console. Test keys work immediately, before any channel is connected.
- Step 02
Connect a channel
Sign in with Facebook or TikTok in the console to connect a WhatsApp number, a Page or a business account. Add a Telegram bot or a Twilio number with its credentials, in the console or with
POST /v1/channels. - Step 03
Send through one endpoint
POST /v1/messagestakes a channel ID, a recipient and a typed content object. The request shape is the same on every channel. - Step 04
Track every delivery
Signed webhooks report sent, delivered, read and failed. The same history is in the console and at
GET /v1/messages.
Message types
What you send is what they see
Each message has a type and a content object under the key of that type. Pick one to see the request body next to the message it produces.
{
"channel": "ch_7Hq2mN5vB8cX1zL0pK3j",
"to": "+971501234567",
"type": "text",
"text": {
"body": "Your order #1042 has shipped. Track it at https://example.com/t/1042",
"preview_url": true
},
"reference": "order-1042"
}Plain text, accepted by every channel type. Set preview_url to let the channel render a link preview.
ChannelsWhatsApp Business, SMS, SMS OTP, Telegram, Messenger, Instagram and TikTok
Console
A console for the parts that are not code
Create keys, connect channels, search the message log, replay webhook deliveries and manage billing. Everything the console shows is also available through the API.
Pricing
Pay per message, or buy messages in bulk
Top up a prepaid wallet from $10 and pay the per-message price of each channel, or buy a package of message credits for volume on your highest-priced channels.
10k messages
$8
$0.0008 per message
- 10,000 outbound messages
- Valid for 3 months from purchase
- Valid on every channel type
100k messages
Featured$60
$0.0006 per message
- 100,000 outbound messages
- Valid for 6 months from purchase
- Valid on every channel type
1m messages
$400
$0.0004 per message
- 1,000,000 outbound messages
- Valid for 12 months from purchase
- Valid on every channel type
Pay as you go
| Channel | Per message |
|---|---|
| WhatsApp Business | $0.001 |
| Telegram | $0.0003 |
| SMS | $0.0005 |
| SMS OTP | $0.0005 |
| Messenger | $0.0005 |
| $0.0005 | |
| TikTok | $0.0005 |
What the price covers
- BilledOutbound messages accepted by the API, at the moment they are accepted.
- FreeInbound messages, test-mode messages, webhooks and the console.
- RefundedAny message that ends as failed, back to the package or wallet it came from.
- SeparateFees that Meta, carriers or other providers charge for the channel itself.
Developer experience
Built to be integrated once and left alone
Signed webhooks, safe retries, a sandbox that behaves like production and errors you can branch on.
Webhooks you can verify
Every delivery is signed with HMAC-SHA256 over the timestamp and the raw body, in the OmniMessage-Signature header. Answer with any 2xx within 10 seconds. Failed deliveries are retried eight times with backoff, from 30 seconds up to 24 hours.
import { createHmac, timingSafeEqual } from 'node:crypto';
// header is "t=<unix seconds>,v1=<hex hmac-sha256>"
export function verifySignature(rawBody, header, secret) {
const parts = header.split(',').map((part) => part.split('='));
const { t, v1 = '' } = Object.fromEntries(parts);
const expected = createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
const matches =
v1.length === expected.length &&
timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
return fresh && matches;
}{
"id": "evt_8Kd2pQ7wN4xB1zR6mT3c",
"object": "event",
"type": "message.delivered",
"mode": "live",
"created_at": "2026-10-05T09:30:02.900Z",
"data": {
"object": {
"id": "msg_2b1Xw9aQ3rT8yU0pL4kZ",
"object": "message",
"status": "delivered",
"reference": "order-1042",
"delivered_at": "2026-10-05T09:30:02.871Z"
}
}
}A test mode that costs nothing
Test keys use built-in sandbox channels, so there is nothing to connect. The last digits of the recipient decide the simulated outcome, and your webhooks fire as they would in production.
curl https://api.omnimessage.co/v1/messages \
-H "Authorization: Bearer om_test_..." \
-H "Content-Type: application/json" \
-d '{
"channel": "ch_test_whatsapp",
"to": "+971501230002",
"type": "text",
"text": { "body": "Hello from the sandbox" }
}'Errors with a type and a code
Every non-2xx response has the same body: a type for the class of failure, a stable code to branch on, the offending param where there is one, and a request_id for support.
{
"error": {
"type": "billing_error",
"code": "insufficient_balance",
"message": "Not enough wallet balance or package credits.",
"request_id": "req_5Vn1cH8jL3qW6yD9sF2k",
"doc_url": "https://omnimessage.co/docs/errors#insufficient_balance"
}
}Idempotent POSTs
Send an
Idempotency-Keyheader and a retry within 24 hours returns the stored response withIdempotent-Replayed: true, without sending or charging twice.Predictable limits
100 requests per second per key on
POST /v1/messages, 20 elsewhere. Every response carriesRateLimit-Remaining, and a 429 carriesRetry-After.Batch sending
POST /v1/messages/batchaccepts up to 100 messages. Each item is accepted, rejected and billed on its own, and the 207 response reports them by index.Scoped keys
Give each key only the scopes it needs, such as
messages:writeorbilling:read, and restrict it to an IP allowlist.
Questions
Before you integrate
The short answers. The documentation has the long ones.
Do I need my own WhatsApp number, bot or SMS number?
Yes. OmniMessage is a bring-your-own-channel gateway: you connect your own WhatsApp Cloud API number, Telegram bot, Twilio number or social account, and keep ownership of it. The channels page lists what each type needs.
What exactly am I billed for?
One charge per outbound message that the API accepts: a package credit if you have one, otherwise the per-message price of the channel type from your wallet. Inbound messages and test-mode messages are free, and a message that ends as failed is refunded automatically.
Are Meta, carrier or provider fees included?
No. The gateway fee covers the API, delivery tracking, webhooks and the console. Fees that Meta, Twilio or another provider charge for the channel itself stay between you and that provider.
How do I test without sending real messages?
Use a key that starts with om_test_. Every account has a sandbox channel per type, such as ch_test_whatsapp. Nothing is delivered or billed and statuses are simulated: a recipient ending in 0000 fails, 0001 stays sent, 0002 is also read, and anything else is delivered within about two seconds.
What happens when my balance runs out?
The API answers 402 insufficient_balance and nothing is queued, so you never owe money after the fact. You can subscribe to the balance.low event or turn on auto-recharge to top up the wallet when it drops below a threshold you choose.
Do I need an SDK?
No. The API is JSON over HTTPS with bearer authentication, so any HTTP client works. The documentation has examples in cURL, Node, Python and PHP.
Send your first message in test mode today
Create an account, copy a test key and call the API before you connect a single channel. Every new account starts with 100 free messages.