Managing Contacts
Contacts are intelligent phone number records that automatically detect messaging capabilities and enable optimized delivery routing across SMS and WhatsApp.
Overview
A Contact in Sent represents more than just a phone number. It includes:
- Validated phone number in multiple formats (E.164, International, National)
- Channel availability - Which channels can reach this contact
- Routing preferences - Optimal channel based on history
- Engagement data - Delivery success patterns
Why Use Contacts?
❌ Without Contacts (Direct Phone Number)
// You handle routing logic
if (await checkWhatsApp(phoneNumber)) {
await sendWhatsApp(phoneNumber, message);
} else {
await sendSMS(phoneNumber, message);
}✅ With Contacts
// Sent handles routing automatically using the phone number
// Contacts are created/updated behind the scenes
await sent.messages.send({
to: [contact.phoneNumber],
template: { id: templateId }
});Creating Contacts
Automatic Creation
Contacts are created automatically when you send to a new phone number:
# Contact will be created automatically
curl -X POST "https://api.sent.dm/v3/messages" \
-H "x-api-key: $SENT_API_KEY" \
-d '{
"to": ["+1234567890"],
"template": {
"id": "tmpl_123"
},
"test_mode": false
}'// First message creates the contact automatically
const response = await client.messages.send({
to: ['+1234567890'],
template: { id: 'tmpl_123' }
});
// Response includes message_id for tracking
console.log(response.data.recipients[0].message_id);# First message creates the contact automatically
response = client.messages.send(
to=["+1234567890"],
template={"id": "tmpl_123"}
)
# Response includes message_id for tracking
print(response.data.recipients[0].message_id)// First message creates the contact automatically
response, err := client.Messages.Send(context.Background(), sentdm.MessageSendParams{
To: []string{"+1234567890"},
Template: sentdm.MessageSendParamsTemplate{
ID: sentdm.String("tmpl_123"),
},
})
// Response includes message_id for tracking
fmt.Println(response.Data.Recipients[0].MessageID)// First message creates the contact automatically
MessageSendParams params = MessageSendParams.builder()
.addTo("+1234567890")
.template(MessageSendParams.Template.builder()
.id("tmpl_123")
.build())
.build();
var response = client.messages().send(params);
// Response includes message_id for tracking
System.out.println(response.data().recipients().get(0).messageId());// First message creates the contact automatically
MessageSendParams parameters = new()
{
To = new List<string> { "+1234567890" },
Template = new MessageSendParamsTemplate { Id = "tmpl_123" }
};
var response = await client.Messages.SendAsync(parameters);
// Response includes message_id for tracking
Console.WriteLine(response.Data.Recipients[0].MessageId);// First message creates the contact automatically
$result = $client->messages->send(
to: ['+1234567890'],
template: ['id' => 'tmpl_123']
);
// Response includes message_id for tracking
echo $result->data->recipients[0]->message_id;# First message creates the contact automatically
result = sent_dm.messages.send(
to: ["+1234567890"],
template: { id: "tmpl_123" }
)
# Response includes message_id for tracking
puts result.data.recipients[0].message_idExplicit Creation
Create contacts before sending for better organization:
curl -X POST "https://api.sent.dm/v3/contacts" \
-H "x-api-key: $SENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+1234567890"
}'const contact = await client.contacts.create({
phoneNumber: '+1234567890'
});
console.log(`Contact created: ${contact.data.id}`);contact = client.contacts.create(
phone_number="+1234567890"
)
print(f"Contact created: {contact.data.id}")contact, err := client.Contacts.Create(context.Background(), sentdm.ContactCreateParams{
PhoneNumber: sentdm.String("+1234567890"),
})
fmt.Println("Contact created:", contact.Data.ID)ContactCreateParams params = ContactCreateParams.builder()
.phoneNumber("+1234567890")
.build();
var contact = client.contacts().create(params);
System.out.println("Contact created: " + contact.data().id());ContactCreateParams parameters = new()
{
PhoneNumber = "+1234567890"
};
var contact = await client.Contacts.CreateAsync(parameters);
Console.WriteLine($"Contact created: {contact.Data.Id}");$contact = $client->contacts->create(
phoneNumber: '+1234567890'
);
echo "Contact created: " . $contact->data->id . "\n";contact = sent_dm.contacts.create(
phone_number: "+1234567890"
)
puts "Contact created: #{contact.data.id}"Contact Lifecycle
Retrieving Contacts
List All Contacts
# List with pagination
curl "https://api.sent.dm/v3/contacts?page=1&pageSize=100" \
-H "x-api-key: $SENT_API_KEY"
# Search contacts
curl "https://api.sent.dm/v3/contacts?page=1&pageSize=100&search=+1234" \
-H "x-api-key: $SENT_API_KEY"// List all contacts
const contacts = await client.contacts.list({
page: 1,
pageSize: 100
});
// Search contacts
const searchResults = await client.contacts.list({
search: '+1234'
});
// Iterate through all pages
for (const contact of contacts.data) {
console.log(`${contact.phoneNumber} - ${contact.availableChannels}`);
}# List all contacts
contacts = client.contacts.list(page=1, page_size=100)
# Search contacts
search_results = client.contacts.list(search="+1234")
# Iterate through results
for contact in contacts.data:
print(f"{contact.phone_number} - {contact.available_channels}")// List all contacts
contacts, err := client.Contacts.List(context.Background(), sentdm.ContactListParams{
Page: sentdm.Int(1),
PageSize: sentdm.Int(100),
})
// Search contacts
searchResults, err := client.Contacts.List(context.Background(), sentdm.ContactListParams{
Search: sentdm.String("+1234"),
})
// Iterate through results
for _, contact := range contacts.Data {
fmt.Printf("%s - %s\n", contact.PhoneNumber, contact.AvailableChannels)
}// List all contacts
ContactListParams params = ContactListParams.builder()
.page(1)
.pageSize(100)
.build();
var contacts = client.contacts().list(params);
// Search contacts
var searchResults = client.contacts().list(ContactListParams.builder()
.search("+1234")
.build());
// Iterate through results
for (var contact : contacts.data()) {
System.out.println(contact.phoneNumber() + " - " + contact.availableChannels());
}// List all contacts
ContactListParams parameters = new()
{
Page = 1,
PageSize = 100
};
var contacts = await client.Contacts.ListAsync(parameters);
// Search contacts
var searchResults = await client.Contacts.ListAsync(new ContactListParams
{
Search = "+1234"
});
// Iterate through results
foreach (var contact in contacts.Data)
{
Console.WriteLine($"{contact.PhoneNumber} - {contact.AvailableChannels}");
}// List all contacts
$contacts = $client->contacts->list(page: 1, pageSize: 100);
// Search contacts
$searchResults = $client->contacts->list(search: '+1234');
// Iterate through results
foreach ($contacts->data as $contact) {
echo "{$contact->phone_number} - {$contact->available_channels}\n";
}# List all contacts
contacts = sent_dm.contacts.list(page: 1, page_size: 100)
# Search contacts
search_results = sent_dm.contacts.list(search: "+1234")
# Iterate through results
contacts.data.each do |contact|
puts "#{contact.phone_number} - #{contact.available_channels}"
endGet Single Contact
curl "https://api.sent.dm/v3/contacts/contact_1234567890" \
-H "x-api-key: $SENT_API_KEY"const contact = await client.contacts.get('contact_1234567890');
console.log('Phone:', contact.data.phoneNumber);
console.log('Channels:', contact.data.availableChannels);
console.log('Default Channel:', contact.data.defaultChannel);contact = client.contacts.get("contact_1234567890")
print(f"Phone: {contact.data.phone_number}")
print(f"Channels: {contact.data.available_channels}")
print(f"Default: {contact.data.default_channel}")contact, err := client.Contacts.Get(context.Background(), "contact_1234567890")
fmt.Println("Phone:", contact.Data.PhoneNumber)
fmt.Println("Channels:", contact.Data.AvailableChannels)
fmt.Println("Default:", contact.Data.DefaultChannel)var contact = client.contacts().get("contact_1234567890");
System.out.println("Phone: " + contact.data().phoneNumber());
System.out.println("Channels: " + contact.data().availableChannels());
System.out.println("Default: " + contact.data().defaultChannel());var contact = await client.Contacts.GetAsync("contact_1234567890");
Console.WriteLine($"Phone: {contact.Data.PhoneNumber}");
Console.WriteLine($"Channels: {contact.Data.AvailableChannels}");
Console.WriteLine($"Default: {contact.Data.DefaultChannel}");$contact = $client->contacts->get("contact_1234567890");
echo "Phone: {$contact->data->phone_number}\n";
echo "Channels: {$contact->data->available_channels}\n";
echo "Default: {$contact->data->default_channel}\n";contact = sent_dm.contacts.get("contact_1234567890")
puts "Phone: #{contact.data.phone_number}"
puts "Channels: #{contact.data.available_channels}"
puts "Default: #{contact.data.default_channel}"Response Structure
{
"success": true,
"data": {
"id": "contact_1234567890",
"phone_number": "+1234567890",
"format_e164": "+1234567890",
"format_international": "+1 234-567-890",
"format_national": "(234) 567-890",
"format_rfc": "tel:+1-234-567-890",
"country_code": "1",
"region_code": "US",
"available_channels": "sms,whatsapp",
"default_channel": "whatsapp",
"opt_out": false,
"is_inherited": false,
"created_at": "2025-01-01T12:00:00Z",
"updated_at": "2025-01-15T08:30:00Z"
},
"error": null,
"meta": {
"request_id": "req_contact_001",
"timestamp": "2026-03-04T11:28:25.2096416+00:00",
"version": "v3"
}
}Updating Contacts
curl -X PATCH "https://api.sent.dm/v3/contacts/contact_1234567890" \
-H "x-api-key: $SENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"default_channel": "whatsapp",
"opt_out": false
}'const updated = await client.contacts.update('contact_1234567890', {
defaultChannel: 'whatsapp',
optOut: false
});updated = client.contacts.update(
"contact_1234567890",
default_channel="whatsapp",
opt_out=False
)updated, err := client.Contacts.Update(context.Background(), "contact_1234567890", sentdm.ContactUpdateParams{
DefaultChannel: sentdm.String("whatsapp"),
OptOut: sentdm.Bool(false),
})ContactUpdateParams params = ContactUpdateParams.builder()
.defaultChannel("whatsapp")
.optOut(false)
.build();
var updated = client.contacts().update("contact_1234567890", params);ContactUpdateParams parameters = new()
{
DefaultChannel = "whatsapp",
OptOut = false
};
var updated = await client.Contacts.UpdateAsync("contact_1234567890", parameters);$updated = $client->contacts->update(
"contact_1234567890",
defaultChannel: 'whatsapp',
optOut: false
);updated = sent_dm.contacts.update(
"contact_1234567890",
default_channel: "whatsapp",
opt_out: false
)Deleting Contacts
curl -X DELETE "https://api.sent.dm/v3/contacts/contact_1234567890" \
-H "x-api-key: $SENT_API_KEY"await client.contacts.delete('contact_1234567890');client.contacts.delete("contact_1234567890")err := client.Contacts.Delete(context.Background(), "contact_1234567890")client.contacts().delete("contact_1234567890");await client.Contacts.DeleteAsync("contact_1234567890");$client->contacts->delete("contact_1234567890");sent_dm.contacts.delete("contact_1234567890")Deleting a contact is permanent. Messages already sent to this contact will retain their delivery records, but you won't be able to reference the contact in future API calls.
Bulk Import
For importing large numbers of contacts, see the Batch Operations guide.
Best Practices
1. Store Contact IDs in Your Database
// Store the phone number for messaging
const user = await db.users.create({
email: 'john@example.com',
phoneNumber: '+1234567890'
});
// Send directly to the phone number
// Contacts are automatically created/updated by the API
await client.messages.send({
to: [user.phoneNumber],
template: { id: 'welcome' }
});2. Respect Channel Preferences
const contact = await client.contacts.get(contactId);
// Check available channels before sending
if (!contact.data.availableChannels.includes('whatsapp')) {
console.log('WhatsApp not available, will use SMS fallback');
}4. Handle Validation Errors
try {
const contact = await client.contacts.create({
phoneNumber: 'invalid-number'
});
} catch (error) {
if (error.code === 'VALIDATION_002') {
// Prompt user to correct their number
showValidationError('Please enter a valid phone number');
}
}Phone Number Formats
Sent automatically normalizes phone numbers:
| Input Format | Normalized (E.164) | Display Format |
|---|---|---|
| +1 234-567-8900 | +12345678900 | +1 234-567-8900 |
| (234) 567-8900 | +12345678900 | +1 234-567-8900 |
| 234-567-8900 | +12345678900 | +1 234-567-8900 |
Always include country codes. Numbers without country codes will be rejected or may be misrouted.
Contact Metadata
Store custom data with contacts:
await client.contacts.update('contact_123', {
metadata: {
customerSince: '2024-01-15',
preferredLanguage: 'es',
lastOrderId: 'order_456'
}
});Next Steps
- Sending Messages - Use contacts to send messages
- Batch Operations - Import contacts in bulk
- Working with Templates - Create message templates