Adding Contacts
Add recipients to your broadcast in batches
Add contacts to your broadcast before sending. Contacts can include personalization variables for customized messages.
Adding Contacts
const result = await zavu.broadcasts.contacts.add(broadcast.id, {
contacts: [
{ recipient: "+14155551234" },
{ recipient: "+14155555678" },
{ recipient: "+14155559012" },
],
});
console.log(`Added: ${result.added}`);
console.log(`Duplicates: ${result.duplicates}`);
console.log(`Invalid: ${result.invalid}`);
Response
JSON{ "added": 3, "duplicates": 0, "invalid": 0, "errors": [] }
With Personalization
Add template variables for each contact to personalize messages:
TypeScriptawait zavu.broadcasts.contacts.add(broadcast.id, { contacts: [ { recipient: "+14155551234", templateVariables: { name: "John Smith", order_id: "ORD-12345", delivery_date: "January 20th", }, }, { recipient: "+14155555678", templateVariables: { name: "Jane Doe", order_id: "ORD-12346", delivery_date: "January 21st", }, }, ], });
The message template Hi {{name}}, your order #{{order_id}} arrives {{delivery_date}}! becomes:
- John: "Hi John Smith, your order #ORD-12345 arrives January 20th!"
- Jane: "Hi Jane Doe, your order #ORD-12346 arrives January 21st!"
Per-contact URL button variables
If the template has a dynamic URL button (e.g., https://example.com/orders/{{1}}), supply each contact's value via templateButtonVariables. Keys are the button index in the template's buttons array ("0", "1", "2").
TypeScriptawait zavu.broadcasts.contacts.add(broadcast.id, { contacts: [ { recipient: "+14155551234", templateVariables: { "1": "John Smith" }, templateButtonVariables: { "0": "ORD-12345" }, }, { recipient: "+14155555678", templateVariables: { "1": "Jane Doe" }, templateButtonVariables: { "0": "ORD-12346" }, }, ], });
When a contact omits templateButtonVariables, the broadcast falls back to the defaults defined on the broadcast itself.
Batch Processing
Add contacts in batches of up to 1,000 per request. For larger lists, make multiple requests:
TypeScriptconst BATCH_SIZE = 1000; async function addAllContacts(broadcastId: string, allContacts: Contact[]) { let totalAdded = 0; for (let i = 0; i < allContacts.length; i += BATCH_SIZE) { const batch = allContacts.slice(i, i + BATCH_SIZE); const result = await zavu.broadcasts.contacts.add(broadcastId, { contacts: batch.map(c => ({ recipient: c.phone, templateVariables: { name: c.name }, })), }); totalAdded += result.added; console.log(`Batch ${Math.floor(i / BATCH_SIZE) + 1}: Added ${result.added} contacts`); } return totalAdded; }
Recipient Formats
| Channel | Format | Example |
|---|---|---|
| SMS | E.164 phone | +14155551234 |
| E.164 phone | +14155551234 | |
| Email address | user@example.com |
Handling Duplicates
The API automatically deduplicates contacts:
- Within request: If the same recipient appears twice in one request, only one is added
- Across requests: If a recipient is already in the broadcast, they won't be added again
JSON{ "added": 8, "duplicates": 2, "invalid": 0, "errors": [] }
Handling Invalid Contacts
Invalid contacts are rejected with detailed errors:
JSON{ "added": 7, "duplicates": 0, "invalid": 3, "errors": [ { "recipient": "invalid-phone", "reason": "Invalid phone number format" }, { "recipient": "+1234", "reason": "Phone number too short" }, { "recipient": "not-an-email", "reason": "Invalid email format" } ] }
Listing Contacts
View contacts in a broadcast:
const contacts = await zavu.broadcasts.contacts.list(broadcast.id, {
limit: 50,
});
for (const contact of contacts.items) {
console.log(`${contact.recipient}: ${contact.status}`);
}
// Paginate through all contacts
if (contacts.nextCursor) {
const nextPage = await zavu.broadcasts.contacts.list(broadcast.id, {
cursor: contacts.nextCursor,
});
}
Response
JSON{ "items": [ { "id": "bc_abc123", "recipient": "+14155551234", "recipientType": "phone", "status": "pending", "templateVariables": { "name": "John" }, "createdAt": "2024-01-15T10:30:00.000Z" }, { "id": "bc_def456", "recipient": "+14155555678", "recipientType": "phone", "status": "pending", "templateVariables": { "name": "Jane" }, "createdAt": "2024-01-15T10:30:00.000Z" } ], "nextCursor": "eyJpZCI6ImJjX2RlZjQ1NiJ9" }
Filtering by Status
Filter contacts by delivery status:
terminalcurl "https://api.zavu.dev/v1/broadcasts/{broadcastId}/contacts?status=failed" \ -H "Authorization: Bearer $ZAVUDEV_API_KEY"
| Status | Description |
|---|---|
pending | Not yet sent |
queued | Message created, waiting to send |
sending | Currently being sent |
delivered | Successfully delivered |
failed | Delivery failed |
skipped | Skipped (broadcast cancelled) |
Removing Contacts
Remove a contact before the broadcast is sent:
TypeScript// The broadcast contact id comes first; the broadcast it belongs to is a param. await zavu.broadcasts.contacts.remove(contact.id, { broadcastId: broadcast.id });
Limits
| Limit | Value | Notes |
|---|---|---|
| Contacts per request | 1,000 | Make multiple requests for larger lists |
| Contacts per broadcast | 1,000 (default) | Contact support to increase this limit |
| Template variable size | 1,024 chars | Per variable |
Next Steps
Sending & SchedulingSend your broadcast or schedule it for later