Example repo: github.com/gokapso/whatsapp-broadcasts-example
Complete workflow
Copy
// Step 1: Create broadcast
const createResponse = await fetch('https://api.kapso.ai/platform/v1/whatsapp/broadcasts', {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
whatsapp_broadcast: {
name: 'July promo',
phone_number_id: '1234567890',
whatsapp_template_id: '7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d'
}
})
});
const { data: broadcast } = await createResponse.json();
const broadcastId = broadcast.id;
// Step 2: Add recipients (repeat for batches > 1000)
await fetch(`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}/recipients`, {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
whatsapp_broadcast: {
recipients: [
{
phone_number: '+14155550123',
components: [
{
type: 'body',
parameters: [
{ type: 'text', parameter_name: 'first_name', text: 'John' },
{ type: 'text', parameter_name: 'discount', text: '50%' }
]
}
]
}
]
}
})
});
// Step 3: Send broadcast
await fetch(`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}/send`, {
method: 'POST',
headers: { 'X-API-Key': 'your-api-key' }
});
// Step 4: Poll for progress
async function waitForCompletion(broadcastId) {
while (true) {
const statusResponse = await fetch(
`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}`,
{ headers: { 'X-API-Key': 'your-api-key' } }
);
const { data } = await statusResponse.json();
if (data.completed_at) {
console.log(`Broadcast complete: ${data.sent_count}/${data.total_recipients} sent`);
break;
}
console.log(`Progress: ${data.sent_count}/${data.total_recipients}`);
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5s
}
}
await waitForCompletion(broadcastId);
Step 1: Create broadcast
Copy
const response = await fetch('https://api.kapso.ai/platform/v1/whatsapp/broadcasts', {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
whatsapp_broadcast: {
name: 'July promo',
phone_number_id: '1234567890',
whatsapp_template_id: '7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d'
}
})
});
const { data } = await response.json();
// data.id = broadcast ID for next steps
// data.status = 'draft'
- Phone number must be production type (not sandbox)
- Template must be approved
Step 2: Add recipients
Add up to 1,000 recipients per request. Repeat for batches over 1,000. Recipients use Meta’s component syntax to populate template variables.Body parameters
For templates with body text variables:Copy
await fetch(`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}/recipients`, {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
whatsapp_broadcast: {
recipients: [
{
phone_number: '+14155550123',
components: [
{
type: 'body',
parameters: [
{ type: 'text', parameter_name: 'first_name', text: 'John' },
{ type: 'text', parameter_name: 'discount', text: '50%' }
]
}
]
},
{
phone_number: '+14155550124',
components: [
{
type: 'body',
parameters: [
{ type: 'text', parameter_name: 'first_name', text: 'Jane' },
{ type: 'text', parameter_name: 'discount', text: '40%' }
]
}
]
}
]
}
})
});
Button parameters
For templates with dynamic button URLs:Copy
await fetch(`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}/recipients`, {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
whatsapp_broadcast: {
recipients: [
{
phone_number: '+14155550123',
components: [
{
type: 'body',
parameters: [
{ type: 'text', parameter_name: 'first_name', text: 'Alicia' },
{ type: 'text', parameter_name: 'discount_code', text: 'JULY25' }
]
},
{
type: 'button',
sub_type: 'url',
index: 0,
parameters: [
{ type: 'text', text: 'promo-code-12345' }
]
}
]
}
]
}
})
});
Media headers
For templates with image/video/document headers:Copy
await fetch(`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}/recipients`, {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
whatsapp_broadcast: {
recipients: [
{
phone_number: '+14155550123',
components: [
{
type: 'header',
parameters: [
{
type: 'image',
image: {
link: 'https://example.com/promo.jpg'
}
}
]
},
{
type: 'body',
parameters: [
{ type: 'text', parameter_name: 'first_name', text: 'Alicia' },
{ type: 'text', parameter_name: 'discount_code', text: 'JULY25' }
]
}
]
}
]
}
})
});
Response format
Copy
{
"data": {
"added": 495,
"duplicates": 5,
"errors": [
"Recipient 3: template parameters invalid - Template requires 2 parameters but 1 provided",
"Recipient 7: invalid phone number format"
]
}
}
Step 3: Send broadcast
Trigger async send job:Copy
const response = await fetch(
`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}/send`,
{
method: 'POST',
headers: {
'X-API-Key': 'your-api-key'
}
}
);
const { data } = await response.json();
// data.status = 'sending'
// data.started_at = timestamp
Step 4: Track progress
Copy
const response = await fetch(
`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}`,
{
headers: {
'X-API-Key': 'your-api-key'
}
}
);
const { data } = await response.json();
Response metrics
Copy
{
"data": {
"id": "5f6a7b8c-9d0e-1f2a-3b4c-5d6e7f8a9b0c",
"name": "July promo",
"status": "sending",
"total_recipients": 1000,
"sent_count": 650,
"failed_count": 50,
"delivered_count": 600,
"read_count": 320,
"responded_count": 45,
"pending_count": 300,
"response_rate": 6.9,
"started_at": "2025-07-15T10:00:00Z",
"completed_at": null
}
}
Status transitions
draft→sending→completedorfailed- Poll every 5-10 seconds during send
- Check
completed_atfor completion
Additional features
List individual recipients
Get detailed per-recipient status:Copy
const response = await fetch(
`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}/recipients?page=1&per_page=20`,
{
headers: {
'X-API-Key': 'your-api-key'
}
}
);
const { data, meta } = await response.json();
Recipient fields
Copy
{
"id": "8c9d0e1f-2a3b-4c5d-6e7f-8a9b0c1d2e3f",
"phone_number": "14155550123",
"status": "sent",
"sent_at": "2025-07-15T10:05:23Z",
"delivered_at": "2025-07-15T10:05:30Z",
"read_at": "2025-07-15T10:12:45Z",
"responded_at": "2025-07-15T10:15:00Z",
"error_message": null,
"template_components": [
{
"type": "body",
"parameters": [
{ "type": "text", "parameter_name": "first_name", "text": "John" },
{ "type": "text", "parameter_name": "discount", "text": "50%" }
]
}
]
}
Batch processing (large campaigns)
For campaigns with 1,000+ recipients:Copy
// Split recipients into chunks of 1000
const chunkSize = 1000;
for (let i = 0; i < allRecipients.length; i += chunkSize) {
const chunk = allRecipients.slice(i, i + chunkSize);
await fetch(`https://api.kapso.ai/platform/v1/whatsapp/broadcasts/${broadcastId}/recipients`, {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({ whatsapp_broadcast: { recipients: chunk } })
});
// Optional: small delay between batches
await new Promise(resolve => setTimeout(resolve, 100));
}

