We use essential cookies to make the site work. With your consent, we also use analytics + marketing cookies.
You will send a WhatsApp template message and receive a signed delivery webhook. All you need is a workspace, an API key, and a terminal.
Create a free workspace, verify your email, and generate a live or test-mode key from the API Keys page.
Nine channels are supported. WhatsApp, SMS and RCS need channel-specific onboarding — the dashboard walks you through it.
One JSON POST to /v1/messages sends the message and returns an ID you can poll or receive via webhook.
Verify the CPaaS-Signature header (HMAC-SHA256) and process delivery events idempotently.
Open the API Keys page in the dashboard, click Create key, and copy the sk_live_… value. Live keys prefixed with sk_test_ route to the sandbox and never leave real messages on the wire.
Store the key in a secret manager or a .env file — never in source control.
The channel field on every message accepts one of nine values. WhatsApp, SMS, and RCS require provider onboarding — the dashboard has a wizard for each.
Either curl or the Node.js SDK — both hit the same idempotent endpoint.
curl https://api.cpaas.io/v1/messages \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 9c3f-1a02" \
-d '{
"channel": "whatsapp",
"to": "+919876543210",
"template": "welcome_v1",
"params": { "name": "Jane" }
}'import { CPaaS } from '@cpaas/node';
const client = new CPaaS({ apiKey: process.env.CPAAS_API_KEY! });
const msg = await client.messages.send({
channel: 'whatsapp',
to: '+919876543210',
template: 'welcome_v1',
params: { name: 'Jane' },
idempotencyKey: '9c3f-1a02',
});
console.log(msg.id, msg.status);The response includes the message id and an initial status of queued. Delivery updates arrive by webhook.
Point a public URL at your workspace webhook endpoint on the dashboard. Every event is signed with HMAC-SHA256 over {timestamp}.{payload}. Verify with timingSafeEqual to prevent timing attacks.
import express from 'express';
import crypto from 'crypto';
const app = express();
const SIGNING_SECRET = process.env.CPAAS_WEBHOOK_SECRET!;
app.post(
'/webhooks/cpaas',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.header('CPaaS-Signature') ?? '';
const timestamp = req.header('CPaaS-Timestamp') ?? '';
const payload = req.body.toString('utf8');
const expected = crypto
.createHmac('sha256', SIGNING_SECRET)
.update(`${timestamp}.${payload}`)
.digest('hex');
const ok = crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex'),
);
if (!ok) return res.status(400).send('invalid signature');
const event = JSON.parse(payload);
switch (event.type) {
case 'message.delivered': /* update DB */ break;
case 'message.failed': /* alert ops */ break;
case 'message.read': /* analytics */ break;
}
res.status(200).send('ok');
},
);
app.listen(3000);Return 2xx within 10 seconds. Non-2xx responses trigger retries with exponential backoff up to 24 hours.