Bulk Sending
For sending templates to many customers, iterate over your customer list with per-customer error handling.
Basic Bulk Send
TypeScript
import { Convoup, ConvoupError } from 'convoup';
const client = new Convoup({
apiKey: process.env.CONVOUP_API_KEY!,
});
const customers = [
{ phone: '+918851479441', invoiceId: 'INV-001', amount: 'Rs. 2,500', pdfUrl: 'https://api.example.com/invoices/INV-001.pdf' },
{ phone: '+919876543210', invoiceId: 'INV-002', amount: 'Rs. 4,800', pdfUrl: 'https://api.example.com/invoices/INV-002.pdf' },
// ... 498 more customers
];
let sent = 0;
let failed = 0;
for (const customer of customers) {
try {
await client.sendInvoice({
to: customer.phone,
template: 'test_welcome_template',
params: [customer.invoiceId, customer.amount],
pdfUrl: customer.pdfUrl,
});
sent++;
} catch (err) {
failed++;
if (err instanceof ConvoupError) {
console.error(`Failed for ${customer.phone}: ${err.code} - ${err.message}`);
if (err.code === 'TEMPLATE_NOT_FOUND') {
console.error('Template not found. Aborting batch.');
break;
}
} else {
console.error(`Unexpected error for ${customer.phone}:`, err);
}
}
}
console.log(`Done. Sent: ${sent}, Failed: ${failed}`);Bulk Send with Rate Limiting
Add delays between sends to avoid hitting rate limits:
TypeScript
function delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
for (const customer of customers) {
try {
await client.sendInvoice({
to: customer.phone,
template: 'test_welcome_template',
params: [customer.invoiceId, customer.amount],
pdfUrl: customer.pdfUrl,
});
sent++;
} catch (err) {
failed++;
if (err instanceof ConvoupError && err.code === 'TEMPLATE_NOT_FOUND') break;
}
// 100ms delay between sends
await delay(100);
} Rate limit numbers not specified
The SDK documentation suggests 100-500ms delays as example guidance, not a documented contract. Actual rate limits depend on your WABA tier and Meta's policies. Start with conservative delays and adjust based on 429 responses.Bulk Send with Concurrency Control
For large batches, send multiple messages in parallel with a concurrency limit:
TypeScript
async function bulkSendWithConcurrency(
customers: Customer[],
concurrency: number,
): Promise<{ sent: number; failed: number }> {
let sent = 0;
let failed = 0;
const chunks: Customer[][] = [];
for (let i = 0; i < customers.length; i += concurrency) {
chunks.push(customers.slice(i, i + concurrency));
}
for (const chunk of chunks) {
const results = await Promise.allSettled(
chunk.map(c =>
client.sendInvoice({
to: c.phone,
template: 'test_welcome_template',
params: [c.invoiceId, c.amount],
pdfUrl: c.pdfUrl,
})
)
);
for (const result of results) {
if (result.status === 'fulfilled') sent++;
else failed++;
}
// Delay between chunks
await delay(500);
}
return { sent, failed };
}
const results = await bulkSendWithConcurrency(customers, 10);
console.log(`Sent: ${results.sent}, Failed: ${results.failed}`);Concurrency Flow
graph TD
A[Customer List] --> B[Split into chunks]
B --> C[Process chunk with Promise.allSettled]
C --> D{More chunks?}
D -->|Yes| E[Delay between chunks]
E --> C
D -->|No| F[Return sent/failed counts]
Error Handling Strategy
| Error Code | Action |
|---|---|
TEMPLATE_NOT_FOUND | Abort the entire batch - template name is wrong |
TEMPLATE_PARAM_MISMATCH | Log and continue - params don't match for this customer |
RECIPIENT_SUPPRESSED | Log and continue - number is blocked |
RATE_LIMITED | Delay and retry |
| Network error | Log and continue - may be transient |
Next Steps
- Error Codes - All error codes and handling patterns
- Dynamic Media Content - Media in template headers
- Client Constructor - SDK initialization options
