The Contacts API allows you to manage contacts in your SMASHSEND account. This API is commonly used by Zapier developers and other integration platforms to sync contact data, create automated workflows, and manage customer information across different systems.
Base URL: https://api.smashsend.com
All API requests must include your API key in the Authorization header. You can manage your API keys in your SMASHSEND dashboard under Settings → API.
Authorization: Bearer sk_live_abc123...
Rate Limits: API requests are limited to ensure service reliability. For Zapier integrations, we recommend using webhook triggers instead of polling for real-time updates.
Lists contacts for the authenticated workspace with cursor-based pagination. Perfect for Zapier “New Contact” triggers and bulk contact synchronization.
Query Parameters
limit
- Number of contacts to return (default: 15, max: 100)
cursor
- Pagination cursor for getting next page
sort
- Sort order: “createdAt.desc” or “createdAt.asc” (default: “createdAt.desc”)
search
- Search contacts by email, name, or phone
status
- Filter by status: “SUBSCRIBED”, “UNSUBSCRIBED”, or “BANNED”
includeCount
- Include total count in response (boolean)
Request
curl "https://api.smashsend.com/v1/contacts?limit=15&sort=createdAt.desc" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"contacts": {
"cursor": "MjAyNS0wNi0wMlQwMDoyMDoxNS42OTVa",
"hasMore": true,
"items": [
{
"id": "ctc_L10vZx0SFrmzKkHwWjoLYSIf",
"createdAt": "2025-06-02T00:35:15.593Z",
"updatedAt": "2025-06-04T04:13:20.114Z",
"properties": {
"avatarUrl": null,
"birthday": null,
"city": null,
"countryCode": "DZ",
"email": "contact@example.com",
"firstName": "John",
"language": "en",
"lastName": "Doe",
"phone": "",
"status": "SUBSCRIBED",
"timezone": "Africa/Algiers",
"company": "ACME Corp"
},
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer"
}
],
"totalCount": 11
}
}
Retrieves a specific contact by ID. Useful for Zapier “Find Contact” actions and getting detailed contact information.
Path Parameters
contactId
- The unique ID of the contact (starts with “ctc_”)
Request
curl "https://api.smashsend.com/v1/contacts/ctc_abc123def456" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"contact": {
"id": "ctc_E7g1zoXJEAkWvgN0yMEIuPOM",
"createdAt": "2025-06-04T05:26:19.247Z",
"updatedAt": "2025-06-04T05:26:20.454Z",
"properties": {
"avatarUrl": "https://storage.googleapis.com/zootools-beta/workspaces/wrk_ENGTK86JEXXckyDVJthKkPer/contacts/ctc_E7g1zoXJEAkWvgN0yMEIuPOM/avatar",
"birthday": null,
"city": null,
"countryCode": "US",
"email": "test2@example.com",
"firstName": "Test2",
"language": "en-US",
"lastName": "User2",
"phone": null,
"status": "SUBSCRIBED",
"timezone": "America/New_York",
"company": "ACME Corp"
},
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer"
}
}
Creates a new contact. This is the most common endpoint used by Zapier integrations to add contacts from other platforms like forms, CRMs, and e-commerce systems.
Request Body Parameters
Important: All contact data must be wrapped in a properties
object.
properties.email
- Contact’s email address (required, must be unique)
properties.firstName
- Contact’s first name (optional)
properties.lastName
- Contact’s last name (optional)
properties.phone
- Contact’s phone number with country code (optional)
properties.avatarUrl
- URL to contact’s profile photo (optional)
properties.countryCode
- Two-letter ISO country code like “US” (optional)
properties.language
- ISO 639-1 language code like “en” or “en-US” (optional)
properties.timezone
- IANA timezone identifier like “America/New_York” (optional)
properties.*
- Any custom properties as key-value pairs within the properties object
Request
curl -X POST "https://api.smashsend.com/v1/contacts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"properties": {
"email": "jane.smith@example.com",
"firstName": "Jane",
"lastName": "Smith",
"phone": "+1987654321",
"countryCode": "US",
"language": "en-US",
"timezone": "America/New_York",
"company": "Zapier Inc",
"jobTitle": "Developer",
"leadSource": "zapier_integration"
}
}'
Response
{
"contact": {
"id": "ctc_B7OSYsnTUVwBPOGrgYTjvSGS",
"createdAt": "2025-06-04T05:25:54.134Z",
"updatedAt": null,
"properties": {
"avatarUrl": null,
"birthday": null,
"city": null,
"countryCode": null,
"email": "test@example.com",
"firstName": "Test",
"language": null,
"lastName": "User",
"phone": null,
"status": "SUBSCRIBED"
},
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer"
}
}
Updates an existing contact. Commonly used in Zapier workflows to sync updated information from other systems.
Request
curl -X PUT "https://api.smashsend.com/v1/contacts/ctc_abc123def456" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"properties": {
"firstName": "John",
"lastName": "Doe Jr.",
"company": "New Company Inc",
"jobTitle": "Senior Manager"
}
}'
Response
{
"contact": {
"id": "ctc_abc123def456",
"createdAt": "2024-03-20T12:00:00Z",
"updatedAt": "2024-03-21T14:45:00Z",
"properties": {
"avatarUrl": "https://example.com/avatar.jpg",
"birthday": null,
"city": null,
"countryCode": "US",
"email": "john.doe@example.com",
"firstName": "John",
"language": "en-US",
"lastName": "Doe Jr.",
"phone": "+1234567890",
"status": "SUBSCRIBED",
"timezone": "America/New_York",
"company": "New Company Inc",
"jobTitle": "Senior Manager",
"leadSource": "website"
},
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer"
}
}
Permanently deletes a contact. Use with caution as this action cannot be undone.
Request
curl -X DELETE "https://api.smashsend.com/v1/contacts/ctc_abc123def456" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"deleted": true
}
Search for contacts by email address. Perfect for Zapier “Find Contact” actions before creating or updating.
Query Parameters
email
- Email address to search for (required)
Request
curl "https://api.smashsend.com/v1/contacts/search?email=john.doe@example.com" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"contact": {
"id": "ctc_abc123def456",
"createdAt": "2024-03-20T12:00:00Z",
"updatedAt": "2024-03-20T12:00:00Z",
"properties": {
"avatarUrl": null,
"birthday": null,
"city": null,
"countryCode": "US",
"email": "john.doe@example.com",
"firstName": "John",
"language": "en-US",
"lastName": "Doe",
"phone": null,
"status": "SUBSCRIBED",
"timezone": "America/New_York",
"company": "ACME Corp"
},
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer"
}
}
The API uses standard HTTP status codes. Common error responses:
400 - Bad Request
{
"statusCode": 400,
"error": "Bad Request",
"message": "Invalid email format"
}
404 - Not Found
{
"statusCode": 404,
"error": "Not Found",
"message": "Contact not found"
}
409 - Conflict
{
"statusCode": 409,
"error": "Conflict",
"message": "Contact with this email already exists"
}
Custom properties allow you to store additional data with contacts. They're commonly used to sync data from CRMs, e-commerce platforms, and other business tools via Zapier.
Before using custom properties in API calls, you need to create them in your SMASHSEND dashboard or via the Contact Properties API. See the Contact Properties API documentation for more details.
Common Custom Property Examples
{
"properties": {
"email": "contact@example.com",
"firstName": "John",
"lastName": "Doe",
"company": "ACME Corp",
"jobTitle": "Marketing Manager",
"leadSource": "website",
"industry": "Technology",
"annualRevenue": "100000",
"isCustomer": true,
"lastPurchaseDate": "2024-03-15"
}
}
CRM Integration Properties
{
"properties": {
"email": "contact@example.com",
"firstName": "John",
"lastName": "Doe",
"company": "ACME Corp",
"jobTitle": "Marketing Manager",
"industry": "Technology",
"annualRevenue": 250000,
"leadScore": 85,
"lastContactDate": "2024-03-15",
"isQualified": true,
"salesRep": "John Smith",
"dealStage": "Proposal"
}
}
E-commerce Integration Properties
{
"properties": {
"email": "customer@example.com",
"firstName": "Jane",
"lastName": "Smith",
"customerSince": "2023-06-15",
"totalOrders": 12,
"lifetimeValue": 1850.00,
"preferredCategory": "Electronics",
"isVip": true,
"lastPurchaseDate": "2024-03-10",
"loyaltyTier": "Gold",
"averageOrderValue": 154.17
}
}
Form Integration Properties
{
"properties": {
"email": "lead@example.com",
"firstName": "Mike",
"lastName": "Johnson",
"formSource": "Contact Us Page",
"referralSource": "Google Ads",
"interests": "Email marketing, automation, analytics",
"budget": "$1000-5000",
"timeline": "Next 3 months",
"hasOptedInMarketing": true,
"companySize": "50-200 employees",
"currentTool": "Mailchimp"
}
}
Multi-Select Properties (Tags)
For multi-select properties (like tags or categories), you can send an array of values to completely replace the contact's current values. This makes syncing from external systems straightforward - just send the desired final state.
{
"properties": {
"email": "contact@example.com",
"tags": ["customer", "enterprise", "priority"],
"interests": ["email-marketing", "automation"],
"categories": ["premium"]
}
}
How it works: When you send an array for a multi-select property, SMASHSEND will replace all existing values with the new ones.
Examples:
// Contact currently has tags: ["customer", "trial"]
// You send: { "tags": ["customer", "enterprise"] }
// Result: Contact will have tags: ["customer", "enterprise"]
// ("trial" is removed, "enterprise" is added)
// Contact currently has tags: ["customer", "trial"]
// You send: { "tags": [] }
// Result: Contact will have no tags (all removed)
// Contact currently has tags: ["customer"]
// You send: { "tags": ["customer"] }
// Result: No change (same values)
Advanced: Granular Control (Add/Remove)
For advanced use cases where you need precise control over what gets added or removed without fetching current values, use the structured format with add
and remove
arrays:
{
"properties": {
"email": "contact@example.com",
"tags": {
"add": ["vip", "enterprise"],
"remove": ["trial", "free"]
},
"interests": {
"add": ["api-access"],
"remove": []
}
}
}
This is useful for webhooks or event-driven updates where you only know what changed, not the complete desired state.
1. Use “Search then Create” Pattern
Always search for existing contacts by email before creating new ones to avoid duplicates.
2. Leverage Custom Properties
Use custom properties to sync additional data from your source systems like CRM fields, e-commerce data, or form responses.
3. Handle Rate Limits
For bulk operations, consider using batch endpoints or implementing delays between requests.
4. Use Webhooks for Real-time Updates
Instead of polling for changes, set up webhooks to get notified when contacts are created, updated, or deleted.
SMASHSEND supports timezone-aware email delivery to maximize engagement by sending emails at optimal times in each contact's local timezone. The timezone
field accepts IANA timezone identifiers and enables smart delivery features.
Timezone Field
Type: String (optional)
Format: IANA timezone identifier (e.g., America/New_York
)
Validation: Must be a valid IANA timezone or null
Default: null
(will be auto-inferred from countryCode
if available)
Supported Timezone Values
SMASHSEND supports all 597 IANA timezone identifiers. Common examples:
North America:
America/New_York # Eastern Time (UTC-05:00/-04:00)
America/Los_Angeles # Pacific Time (UTC-08:00/-07:00)
America/Chicago # Central Time (UTC-06:00/-05:00)
America/Denver # Mountain Time (UTC-07:00/-06:00)
America/Toronto # Eastern Time Canada
America/Vancouver # Pacific Time Canada
Europe:
Europe/London # Greenwich Mean Time (UTC+00:00/+01:00)
Europe/Paris # Central European Time (UTC+01:00/+02:00)
Europe/Berlin # Central European Time (UTC+01:00/+02:00)
Europe/Rome # Central European Time (UTC+01:00/+02:00)
Europe/Madrid # Central European Time (UTC+01:00/+02:00)
Europe/Amsterdam # Central European Time (UTC+01:00/+02:00)
Asia Pacific:
Asia/Tokyo # Japan Standard Time (UTC+09:00)
Asia/Shanghai # China Standard Time (UTC+08:00)
Asia/Singapore # Singapore Standard Time (UTC+08:00)
Asia/Seoul # Korea Standard Time (UTC+09:00)
Asia/Kolkata # India Standard Time (UTC+05:30)
Asia/Dubai # Gulf Standard Time (UTC+04:00)
Australia/Sydney # Australian Eastern Time (UTC+10:00/+11:00)
Australia/Melbourne # Australian Eastern Time (UTC+10:00/+11:00)
Pacific/Auckland # New Zealand Time (UTC+12:00/+13:00)
Getting Timezone Data from Libraries
// Install: npm install moment-timezone
import moment from 'moment-timezone';
// Get all timezone names (597 total)
const allTimezones = moment.tz.names();
console.log(allTimezones); // ["Africa/Abidjan", "Africa/Accra", ...]
// Get popular timezones for dropdowns
const popularTimezones = [
'America/New_York', 'America/Los_Angeles', 'Europe/London',
'Europe/Paris', 'Asia/Tokyo', 'Australia/Sydney'
];
// Validate timezone
const isValid = !!moment.tz.zone('America/New_York'); // true
const isInvalid = !!moment.tz.zone('Invalid/Zone'); // false
// Get current offset for timezone
const offset = moment().tz('America/New_York').format('Z'); // "-04:00"
// Browser detection (no library needed)
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(userTimezone); // e.g., "America/New_York"
Usage Examples
Create contact with timezone:
{
"properties": {
"email": "user@example.com",
"firstName": "John",
"lastName": "Doe",
"timezone": "America/New_York",
"countryCode": "US",
"language": "en-US"
}
}
Update contact timezone:
{
"properties": {
"timezone": "Europe/London"
}
}
Validation & Error Handling
Invalid timezone values return a 400 Bad Request
error:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Invalid/Timezone is not a valid IANA timezone identifier"
}
Valid Examples:
✅ “America/New_York”
✅ “Europe/London”
✅ “Asia/Tokyo”
✅ null
(will be auto-inferred)
Invalid Examples:
❌ “EST”
(use America/New_York
instead)
❌ “GMT+5”
(use Asia/Kolkata
instead)
❌ “Invalid/Zone”
Auto-Detection & Smart Features
Automatic Timezone Inference (Best Effort):
When timezone
is not provided but countryCode
is available, SMASHSEND automatically infers the most likely timezone as a best effort. However, this may not be accurate for countries with multiple timezones.
⚠️ Important: For optimal email delivery, always provide the explicit timezone
when possible. Inference is a fallback feature and may not be accurate for all users.
{
"properties": {
"email": "user@example.com",
"countryCode": "US" // Will infer "America/New_York" (Eastern Time)
// But user might be in Pacific Time!
}
}
// Better approach - detect timezone explicitly:
{
"properties": {
"email": "user@example.com",
"countryCode": "US",
"timezone": "America/Los_Angeles" // Explicit timezone is more accurate
}
}
Inference Limitations:
• Multi-timezone countries: US has 6+ timezones, Russia has 11
• Default bias: We default to the most populous timezone
• Border regions: Users near timezone boundaries may be inaccurate
• Travelers: Current location may differ from home timezone
Best Practice: Use browser detection or user input to get the actual timezone rather than relying on country-based inference.
Smart Email Delivery:
• Emails are sent during optimal hours (7 AM - 6 PM) in the contact's timezone
• Automatic DST (Daylight Saving Time) handling
• Improved open rates through timezone-aware scheduling
• Better user experience with localized send times
The countryCode
field stores the contact's country using ISO 3166-1 alpha-2 country codes.
Country Code Field
Type: String (optional)
Format: Two-letter ISO 3166-1 alpha-2 code (e.g., US
, GB
, CA
)
Validation: Must be a valid ISO country code
Case: Uppercase (automatically normalized)
Common Country Codes
US # United States
CA # Canada
GB # United Kingdom
DE # Germany
FR # France
AU # Australia
JP # Japan
BR # Brazil
IN # India
MX # Mexico
Getting Country Data from Browser
// Get user's country from locale
const userLocale = navigator.language || navigator.userLanguage;
const countryCode = userLocale.split('-')[1]; // e.g., "en-US" → "US"
// Using Geolocation API (requires user permission)
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(async (position) => {
// Use a geocoding service to get country from coordinates
const response = await fetch(`https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${position.coords.latitude}&longitude=${position.coords.longitude}`);
const data = await response.json();
console.log(data.countryCode); // e.g., "US"
});
}
The language
field stores the contact's preferred language using ISO 639-1 language codes.
Language Field
Type: String (optional)
Format: ISO 639-1 two-letter code (e.g., en
, es
, fr
) or locale format (e.g., en-US
, pt-BR
)
Validation: Must be a valid ISO language code
Case: Lowercase (automatically normalized)
Common Language Codes
en # English
es # Spanish
fr # French
de # German
it # Italian
pt # Portuguese
ja # Japanese
ko # Korean
zh # Chinese
ar # Arabic
ru # Russian
hi # Hindi
Locale Format (with country):
en-US # English (United States)
en-GB # English (United Kingdom)
es-ES # Spanish (Spain)
es-MX # Spanish (Mexico)
pt-BR # Portuguese (Brazil)
zh-CN # Chinese (Simplified)
Getting Language Data from Browser
// Get user's preferred language
const userLanguage = navigator.language || navigator.userLanguage;
console.log(userLanguage); // e.g., "en-US", "es-MX", "fr-FR"
// Extract just the language code
const languageCode = userLanguage.split('-')[0]; // e.g., "en-US" → "en"
// Get all user languages (in order of preference)
const userLanguages = navigator.languages;
console.log(userLanguages); // e.g., ["en-US", "en", "es"]
Here's a complete example showing how to detect and send all geographic/locale data from a web form using explicit detection (recommended):
// RECOMMENDED: Detect user's locale information explicitly
async function createContactWithLocaleData(email, firstName, lastName) {
// ✅ BEST: Detect timezone explicitly from browser
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
// ✅ BEST: Detect language from browser preferences
const language = navigator.language || navigator.userLanguage;
// ✅ BETTER: Extract country from language if available
const countryCode = language.includes('-') ? language.split('-')[1] : null;
// Create contact with explicit data (most accurate)
const response = await fetch('/v1/contacts', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
properties: {
email: email,
firstName: firstName,
lastName: lastName,
timezone: timezone, // ✅ Explicit timezone (most accurate)
language: language, // ✅ User's actual language preference
countryCode: countryCode, // ✅ Detected from locale
detectionMethod: "browser" // Custom property for tracking
}
})
});
return response.json();
}
// FALLBACK: If you only have country data
async function createContactWithCountryOnly(email, firstName, lastName, countryCode) {
const response = await fetch('/v1/contacts', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
properties: {
email: email,
firstName: firstName,
lastName: lastName,
countryCode: countryCode, // ⚠️ SMASHSEND will infer timezone (best effort)
detectionMethod: "country_inference"
}
})
});
return response.json();
}
// Usage examples
createContactWithLocaleData('user@example.com', 'John', 'Doe'); // ✅ Recommended
createContactWithCountryOnly('user@example.com', 'Jane', 'Smith', 'US'); // ⚠️ Fallback
Accuracy Recommendations
1. Always Use Explicit Timezone Detection:
Use Intl.DateTimeFormat().resolvedOptions().timeZone
in browsers or equivalent methods in your platform to get the user's actual timezone.
2. Validate Before Sending:
Use timezone libraries to validate timezone identifiers before sending them to SMASHSEND to avoid validation errors.
3. Handle Multi-Timezone Countries:
Countries like the US, Russia, Canada, and Australia have multiple timezones. Always ask users or detect their specific timezone rather than assuming from country alone.
Benefits of Complete Locale Data
Enhanced Personalization:
• Send emails in the contact's preferred language
• Respect cultural preferences and holidays
• Optimize send times for local timezones
• Improve deliverability with localized content
Better Analytics:
• Segment audiences by geography and language
• Track engagement by timezone and country
• Optimize campaigns for different regions
• Understand global customer distribution
Compliance & UX:
• Respect time-based communication preferences
• Comply with regional regulations (GDPR, CAN-SPAM)
• Provide better user experience with localized timing
• Reduce unsubscribes through timezone awareness
Recommended Libraries by Language
JavaScript/TypeScript:
• moment-timezone: Full timezone support with DST handling
• date-fns-tz: Lightweight timezone utilities
• luxon: Modern date/time library with timezone support
• Intl.DateTimeFormat: Built-in browser API
Python:
• pytz: Comprehensive timezone library
• zoneinfo: Built-in timezone support (Python 3.9+)
• pendulum: Modern date/time library
Other Languages:
• Ruby: tzinfo gem or built-in Time class
• PHP: Carbon library or built-in DateTime
• Java: java.time package (built-in)
• C#: NodaTime library or TimeZoneInfo
• Go: time package (built-in) + go-timezone
• Rust: chrono-tz crate
Country & Language Detection Libraries
JavaScript:
• country-list: ISO country codes and names
• i18n-iso-countries: Country code utilities
• iso-639-1: Language code utilities
• Intl.Locale: Built-in locale handling
GeoIP APIs for Country Detection:
• MaxMind GeoIP2: Professional IP geolocation
• IPinfo.io: IP geolocation with free tier
• BigDataCloud: Free IP geolocation API
• ipapi.co: Simple IP geolocation
• Browser Geolocation API: GPS-based (requires permission)