Contacts
Manage contacts and recipient information
Contacts are automatically created when you send messages. Each contact represents a unique recipient (phone number or email) and stores metadata about their messaging preferences and history.
How Contacts Work
When you send a message to a new recipient, Zavu automatically:
- Creates a contact record
- Detects the country from the phone number
- Determines available messaging channels
- Captures the WhatsApp profile name (if available)
TypeScript// Sending to a new recipient creates a contact const message = await zavu.messages.send({ to: "+14155551234", text: "Welcome!", }); // Contact is now available const contact = await zavu.contacts.retrieveByPhone("+14155551234"); console.log(contact.id); // "con_abc123"
Contact Properties
| Property | Description |
|---|---|
id | Unique contact identifier |
phoneNumber | E.164 formatted phone number |
countryCode | Two-letter country code (e.g., "US") |
profileName | WhatsApp display name (if available) |
availableChannels | Channels this contact can receive (sms, whatsapp, etc.) |
defaultChannel | Preferred channel for auto-routing |
verified | Whether the contact has been verified |
metadata | Custom key-value data |
Get Contact by ID
import Zavudev from '@zavudev/sdk';
const zavu = new Zavudev();
const contact = await zavu.contacts.retrieve("con_abc123");
console.log(`Phone: ${contact.phoneNumber}`);
console.log(`Country: ${contact.countryCode}`);
console.log(`Channels: ${contact.availableChannels.join(", ")}`);
console.log(`Profile: ${contact.profileName || "Unknown"}`);
Response
JSON{ "id": "con_abc123", "phoneNumber": "+14155551234", "countryCode": "US", "profileName": "John Doe", "availableChannels": ["sms", "whatsapp"], "defaultChannel": "whatsapp", "verified": true, "metadata": { "tier": "premium", "source": "website" }, "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-15T12:00:00.000Z" }
Get Contact by Phone Number
Look up a contact using their phone number:
const contact = await zavu.contacts.retrieveByPhone("+14155551234");
if (contact) {
console.log(`Found contact: ${contact.id}`);
console.log(`Available channels: ${contact.availableChannels}`);
} else {
console.log("Contact not found");
}
List Contacts
Retrieve all contacts with pagination:
// List all contacts
const { items, nextCursor } = await zavu.contacts.list({
limit: 50,
});
for (const contact of items) {
console.log(`${contact.id}: ${contact.phoneNumber}`);
}
// Paginate through all contacts
let cursor: string | undefined;
const allContacts = [];
do {
const result = await zavu.contacts.list({ cursor, limit: 100 });
allContacts.push(...result.items);
cursor = result.nextCursor ?? undefined;
} while (cursor);
console.log(`Total contacts: ${allContacts.length}`);
Filter by Phone Number
phoneNumber is an exact match on the contact's primary phone number, in
E.164. It is not a prefix filter — use search for partial matches.
TypeScriptconst { items } = await zavu.contacts.list({ phoneNumber: "+14155551234", });
Search
search matches the contact's name — both displayName and the WhatsApp profile
name — as well as its phone numbers and email addresses. It is case- and
accent-insensitive, so jose finds "José".
TypeScriptconst { items } = await zavu.contacts.list({ search: "marta", limit: 25 });
A phone number also matches on a trailing fragment, which is how people usually remember them:
TypeScript// finds +14155551234 const { items } = await zavu.contacts.list({ search: "5551234" });
Filter by Tag
Tags group contacts into an audience you send to more than once. Filter by name:
TypeScriptconst { items } = await zavu.contacts.list({ tag: "vip" });
Repeat the parameter to require every tag, not any of them:
terminalcurl "https://api.zavu.dev/v1/contacts?tag=vip&tag=chile" \ -H "Authorization: Bearer $ZAVUDEV_API_KEY"
Update Contact
Update a contact's default channel or metadata:
const contact = await zavu.contacts.update("con_abc123", {
defaultChannel: "whatsapp",
metadata: {
name: "John Doe",
tier: "premium",
source: "mobile_app",
},
});
console.log(`Updated default channel: ${contact.defaultChannel}`);
Updateable Fields
| Field | Description |
|---|---|
displayName | The contact's name. Pass null to clear it and fall back to the identifier. |
defaultChannel | Preferred channel for smart routing (sms, whatsapp, telegram, email) |
metadata | Custom key-value pairs (merged with existing metadata) |
Contact Metadata
Store custom data on contacts for personalization and segmentation:
TypeScript// Add customer data await zavu.contacts.update("con_abc123", { metadata: { customerId: "cust_12345", plan: "enterprise", signupDate: "2024-01-15", preferredLanguage: "es", }, }); // Use in messages const contact = await zavu.contacts.retrieve("con_abc123"); const message = await zavu.messages.send({ to: contact.phoneNumber, text: `Hola ${contact.metadata?.customerId}! Your ${contact.metadata?.plan} plan is active.`, });
Available Channels
The availableChannels array indicates which channels can reach this contact:
| Channel | When Available |
|---|---|
sms | Valid mobile or landline number |
whatsapp | Contact has WhatsApp (detected on first message or reply) |
telegram | Contact has connected via Telegram bot |
email | Contact has email address on file |
TypeScriptconst contact = await zavu.contacts.retrieve("con_abc123"); if (contact.availableChannels.includes("whatsapp")) { // Send via WhatsApp for richer experience await zavu.messages.send({ to: contact.phoneNumber, channel: "whatsapp", text: "Hello via WhatsApp!", }); } else { // Fall back to SMS await zavu.messages.send({ to: contact.phoneNumber, channel: "sms", text: "Hello via SMS!", }); }
Phone Number Introspection
Validate a phone number and check available channels without creating a contact:
const result = await zavu.introspect.validatePhone({
phoneNumber: "+14155551234",
});
console.log(`Valid: ${result.validNumber}`);
console.log(`Country: ${result.countryCode}`);
console.log(`Format: ${result.nationalFormat}`);
console.log(`Type: ${result.lineType}`);
console.log(`Carrier: ${result.carrier?.name}`);
console.log(`Channels: ${result.availableChannels}`);
Response
JSON{ "phoneNumber": "+14155551234", "countryCode": "US", "validNumber": true, "nationalFormat": "(415) 555-1234", "lineType": "mobile", "carrier": { "name": "Verizon Wireless", "type": "mobile" }, "availableChannels": ["sms", "whatsapp"] }
Complete Example
TypeScriptimport Zavudev from '@zavudev/sdk'; const zavu = new Zavudev(); async function processNewCustomer(phone: string, customerData: { name: string; email: string; plan: string; }) { // 1. Validate the phone number const introspection = await zavu.introspect.validatePhone({ phoneNumber: phone }); if (!introspection.validNumber) { throw new Error("Invalid phone number"); } console.log(`Valid ${introspection.lineType} number from ${introspection.countryCode}`); // 2. Send welcome message (creates contact automatically) const message = await zavu.messages.send({ to: phone, channel: "auto", // Smart routing based on available channels text: `Welcome ${customerData.name}! Your ${customerData.plan} account is ready.`, }); console.log(`Welcome message sent: ${message.id}`); // 3. Update contact with customer data const contact = await zavu.contacts.retrieveByPhone(phone); await zavu.contacts.update(contact.id, { defaultChannel: introspection.availableChannels.includes("whatsapp") ? "whatsapp" : "sms", metadata: { name: customerData.name, email: customerData.email, plan: customerData.plan, signupDate: new Date().toISOString(), }, }); console.log(`Contact updated: ${contact.id}`); return contact; } // Usage processNewCustomer("+14155551234", { name: "John Doe", email: "john@example.com", plan: "premium", });
Next Steps
Learn how defaultChannel affects message routing
Send messages to many contacts at once
Validate and lookup phone numbers
Receive updates when contacts reply
API Reference
Manage contacts programmatically:
- List contacts — paginated list, with
searchover name, phone and email - Get a contact — retrieve a contact by ID
- Get contact by phone — lookup a contact by phone number
- Update a contact — set the name, default channel, or metadata
- Delete a contact — permanently remove a contact