People API Guide
People API Guide
The People API is the core of Sure Send CRM, allowing you to manage contacts, leads, and customers programmatically. This guide covers everything you need to know about creating, updating, and organizing your contacts.
Overview
People (also called contacts or leads) represent individuals in your CRM. Each person can have:
- Basic information (name, company)
- Multiple emails, phones, and addresses
- Tags for categorization
- Custom fields for additional data
- Pipeline stage and assignment
- Source tracking
Creating People
Basic Person Creation
Endpoint: POST /api/partner/people
curl -X POST https://api.suresend.ai/api/partner/people \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Jane",
"lastName": "Doe",
"emails": [
{
"value": "[email protected]",
"isPrimary": true
}
]
}'Response:
{
"id": "person-uuid",
"firstName": "Jane",
"lastName": "Doe",
"name": "Jane Doe",
"emails": [
{
"value": "[email protected]",
"type": "work",
"status": "active",
"isPrimary": true
}
],
"phones": [],
"addresses": [],
"tags": [],
"stage": null,
"source": null,
"createdAt": "2025-10-16T12:00:00Z",
"updatedAt": "2025-10-16T12:00:00Z"
}Full Contact with All Details
curl -X POST https://api.suresend.ai/api/partner/people \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"firstName": "John",
"lastName": "Smith",
"companyName": "Acme Corp",
"stage": "Lead",
"source": "Website Form",
"averagePrice": 350000,
"assignedUserId": "user-uuid",
"emails": [
{
"value": "[email protected]",
"type": "work",
"isPrimary": true
},
{
"value": "[email protected]",
"type": "home"
}
],
"phones": [
{
"value": "+1-555-1234",
"type": "mobile",
"isPrimary": true
},
{
"value": "+1-555-5678",
"type": "work"
}
],
"addresses": [
{
"type": "work",
"street": "123 Business St",
"city": "Portland",
"state": "OR",
"code": "97201",
"country": "US",
"isPrimary": true
}
],
"tags": ["hot-lead", "buyer", "portland-area"]
}'Deduplication
Sure Send CRM automatically deduplicates contacts by email address:
- If an email already exists, the API returns the existing person
- Use
PUT /people/{id}to update existing contacts - This prevents duplicate contacts in your CRM
Retrieving People
List All People
Endpoint: GET /api/partner/people
curl "https://api.suresend.ai/api/partner/people?page=1&limit=50" \
-H "Authorization: Bearer YOUR_API_TOKEN"Query Parameters:
page- Page number (default: 1)limit- Items per page (default: 25, max: 100)email- Filter by email address (partial, case-insensitive match)phone- Filter by phone number (flexible formatting)includeTrash- Include soft-deleted records (default: false)
Response:
{
"people": [
{
"id": "person-uuid",
"firstName": "Jane",
"lastName": "Doe",
"name": "Jane Doe",
"emails": [...],
"phones": [...],
"addresses": [...],
"tags": ["buyer"],
"stage": "Lead",
"source": "Website"
}
],
"meta": {
"total_count": 250,
"current_page": 1,
"total_pages": 5,
"per_page": 50
}
}Get a Specific Person
Endpoint: GET /api/partner/people/{id}
curl https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN"Search by Email
Endpoint: GET /api/partner/people?email={email}
Search for people by email address (partial, case-insensitive match):
curl "https://api.suresend.ai/api/partner/[email protected]" \
-H "Authorization: Bearer YOUR_API_TOKEN"This will return any person with an email address matching "[email protected]". The search is:
- Partial match -
email=johnwill match[email protected],[email protected], etc. - Case-insensitive -
email=JOHNmatches[email protected]
Search by Phone
Endpoint: GET /api/partner/people?phone={phone}
Search for people by phone number with flexible formatting:
curl "https://api.suresend.ai/api/partner/people?phone=555-1234" \
-H "Authorization: Bearer YOUR_API_TOKEN"The phone search normalizes digits and handles various formats:
phone=5551234matches(555) 123-4567,555-123-4567,+1-555-123-4567- Formatting characters (dashes, parentheses, spaces) are ignored
- Partial matches supported -
555will match all numbers containing "555"
Include Deleted Records
Endpoint: GET /api/partner/people?includeTrash=true
Include soft-deleted people in results:
curl "https://api.suresend.ai/api/partner/people?includeTrash=true" \
-H "Authorization: Bearer YOUR_API_TOKEN"By default, soft-deleted records are excluded. Set includeTrash=true to include them.
Updating People
Partial Updates
Endpoint: PUT /api/partner/people/{id}
Only provide fields you want to change - all fields are optional:
curl -X PUT https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Jane",
"stage": "Qualified"
}'Updating Contact Information
Update Email:
curl -X PUT https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"emails": [
{
"value": "[email protected]",
"type": "work",
"isPrimary": true
}
]
}'Update Phone:
curl -X PUT https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phones": [
{
"value": "+1-555-9999",
"type": "mobile",
"isPrimary": true
}
]
}'Update Address:
curl -X PUT https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"addresses": [
{
"type": "home",
"street": "456 New St",
"city": "Seattle",
"state": "WA",
"code": "98101",
"isPrimary": true
}
]
}'Working with Tags
Tags help you categorize and filter contacts. Common use cases:
- Segmentation (buyer, seller, investor)
- Lead quality (hot-lead, warm-lead, cold-lead)
- Marketing campaigns (spring-2025, facebook-ad)
- Behavioral tracking (viewed-property, requested-info)
Apply Tags (Add Without Removing)
Endpoint: POST /api/partner/people/{id}/tags/apply
curl -X POST https://api.suresend.ai/api/partner/people/person-uuid/tags/apply \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tags": ["vip", "portland-buyer", "hot-lead"]
}'This adds the tags without removing existing ones.
Remove Tags
Endpoint: POST /api/partner/people/{id}/tags/delete
curl -X POST https://api.suresend.ai/api/partner/people/person-uuid/tags/delete \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tags": ["cold-lead", "expired-campaign"]
}'Replace All Tags
Use PUT /people/{id} with mergeTags=false (default):
curl -X PUT "https://api.suresend.ai/api/partner/people/person-uuid?mergeTags=false" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tags": ["active-buyer"]
}'Add Tags While Keeping Existing
Use PUT /people/{id} with mergeTags=true:
curl -X PUT "https://api.suresend.ai/api/partner/people/person-uuid?mergeTags=true" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tags": ["new-tag"]
}'Email, Phone, and Address Types
Email Types
work- Work emailhome- Personal emailother- Other email
Email Status
active- Valid, can receive emailsbounced- Email bounced, invalidunsubscribed- User unsubscribed
Phone Types
mobile- Mobile/cell phonework- Work phonehome- Home phoneother- Other phone
Phone Status
active- Valid, can receive calls/textsdisconnected- Phone number no longer validdo-not-call- User requested no calls
Address Types
home- Home addresswork- Work addressother- Other address
Primary Contact Methods
Each person can have one primary email, phone, and address:
{
"emails": [
{
"value": "[email protected]",
"isPrimary": true
},
{
"value": "[email protected]",
"isPrimary": false
}
]
}Pipeline Management
Stages
Track where contacts are in your sales pipeline:
Common stages:
Lead- New lead, not qualifiedQualified- Lead is qualifiedProposal- Proposal sentNegotiation- In negotiationClosed Won- Deal closed successfullyClosed Lost- Deal lost
curl -X PUT https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"stage": "Qualified"
}'Assignment
Assign contacts to specific users:
curl -X PUT https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"assignedUserId": "user-uuid"
}'Source Tracking
Track where leads come from:
curl -X PUT https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source": "Facebook Ad Campaign"
}'Custom Fields
Extend person records with custom data fields. See Custom Fields Guide for details.
curl -X PUT https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customFields": {
"property_budget": 500000,
"preferred_location": "Downtown Portland",
"move_in_timeline": "3-6 months"
}
}'Deleting People
Endpoint: DELETE /api/partner/people/{id}
curl -X DELETE https://api.suresend.ai/api/partner/people/person-uuid \
-H "Authorization: Bearer YOUR_API_TOKEN"⚠️ Warning: Deleting a person is permanent and cannot be undone. All associated data (notes, tasks, events) will also be deleted.
Common Use Cases
1. Find Contact by Email
Check if a contact exists before creating:
const axios = require('axios');
const API_TOKEN = process.env.API_TOKEN;
const API_URL = 'https://api.suresend.ai/api/partner';
async function findOrCreateContact(email, contactData) {
// Search for existing contact by email
const searchResponse = await axios.get(`${API_URL}/people`, {
params: { email },
headers: { Authorization: `Bearer ${API_TOKEN}` }
});
if (searchResponse.data.people.length > 0) {
// Contact exists, return the first match
console.log('Contact found:', searchResponse.data.people[0].name);
return searchResponse.data.people[0];
}
// Contact doesn't exist, create new
const createResponse = await axios.post(`${API_URL}/people`, contactData, {
headers: { Authorization: `Bearer ${API_TOKEN}` }
});
console.log('Contact created:', createResponse.data.name);
return createResponse.data;
}
// Usage
findOrCreateContact('[email protected]', {
firstName: 'John',
lastName: 'Doe',
emails: [{ value: '[email protected]', isPrimary: true }]
});2. Import Contacts from CSV
const fs = require('fs');
const csv = require('csv-parser');
const axios = require('axios');
const API_TOKEN = process.env.API_TOKEN;
const API_URL = 'https://api.suresend.ai/api/partner';
async function importContacts(csvFile) {
const contacts = [];
fs.createReadStream(csvFile)
.pipe(csv())
.on('data', (row) => {
contacts.push({
firstName: row['First Name'],
lastName: row['Last Name'],
emails: [{ value: row['Email'], isPrimary: true }],
phones: [{ value: row['Phone'], type: 'mobile', isPrimary: true }],
companyName: row['Company'],
source: 'CSV Import'
});
})
.on('end', async () => {
for (const contact of contacts) {
try {
await axios.post(`${API_URL}/people`, contact, {
headers: { Authorization: `Bearer ${API_TOKEN}` }
});
console.log(`✓ Imported: ${contact.firstName} ${contact.lastName}`);
} catch (error) {
console.error(`✗ Failed: ${contact.firstName} ${contact.lastName}`, error.message);
}
}
});
}
importContacts('contacts.csv');2. Sync Contacts to External System
const axios = require('axios');
const API_TOKEN = process.env.API_TOKEN;
const API_URL = 'https://api.suresend.ai/api/partner';
async function syncContacts() {
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await axios.get(`${API_URL}/people`, {
params: { page, limit: 100 },
headers: { Authorization: `Bearer ${API_TOKEN}` }
});
const { people, meta } = response.data;
// Sync to your external system
for (const person of people) {
await syncToExternalSystem(person);
}
hasMore = page < meta.total_pages;
page++;
}
}
async function syncToExternalSystem(person) {
// Your sync logic here
console.log('Syncing:', person.name);
}
syncContacts();3. Segment Contacts by Tags
async function getHotLeads() {
let page = 1;
let hotLeads = [];
while (true) {
const response = await axios.get(`${API_URL}/people`, {
params: { page, limit: 100 },
headers: { Authorization: `Bearer ${API_TOKEN}` }
});
const { people, meta } = response.data;
// Filter by tag
const filtered = people.filter(p =>
p.tags && p.tags.includes('hot-lead')
);
hotLeads = hotLeads.concat(filtered);
if (page >= meta.total_pages) break;
page++;
}
return hotLeads;
}
getHotLeads().then(leads => {
console.log(`Found ${leads.length} hot leads`);
});4. Bulk Update Contact Stages
async function promoteQualifiedLeads() {
const response = await axios.get(`${API_URL}/people`, {
params: { limit: 100 },
headers: { Authorization: `Bearer ${API_TOKEN}` }
});
const qualifiedLeads = response.data.people.filter(p =>
p.stage === 'Qualified' && p.tags.includes('hot-lead')
);
for (const lead of qualifiedLeads) {
await axios.put(`${API_URL}/people/${lead.id}`,
{ stage: 'Proposal' },
{ headers: { Authorization: `Bearer ${API_TOKEN}` } }
);
console.log(`Promoted ${lead.name} to Proposal stage`);
}
}5. Auto-Tag Based on Behavior
// Run this when you receive a webhook for page views
async function autoTagBasedOnBehavior(personId, pageUrl) {
const tags = [];
// Tag based on page viewed
if (pageUrl.includes('/properties/luxury')) {
tags.push('luxury-buyer');
}
if (pageUrl.includes('/properties/commercial')) {
tags.push('commercial-buyer');
}
if (pageUrl.includes('/neighborhoods/downtown')) {
tags.push('downtown-interest');
}
if (tags.length > 0) {
await axios.post(
`${API_URL}/people/${personId}/tags/apply`,
{ tags },
{ headers: { Authorization: `Bearer ${API_TOKEN}` } }
);
console.log(`Auto-tagged person ${personId}:`, tags);
}
}Best Practices
Data Quality
- Always provide primary contact method - Mark at least one email/phone as primary
- Validate email formats - Use regex or validation library before submitting
- Normalize phone numbers - Use consistent format (E.164 recommended)
- Clean up duplicates - Leverage deduplication by email
- Keep data current - Regularly update contact information
Performance
- Use pagination - Don't fetch all contacts at once
- Batch operations - Group updates when possible
- Cache frequently accessed data - Reduce API calls
- Use webhooks - Get real-time updates instead of polling
- Implement rate limiting - Respect API rate limits
Tagging Strategy
- Use consistent naming - Lowercase with hyphens (e.g., "hot-lead")
- Create tag taxonomy - Organize tags by category
- Don't over-tag - Keep tags focused and meaningful
- Clean up old tags - Remove outdated or unused tags
- Document tag meanings - Maintain a tag glossary
Security
- Never expose API tokens - Keep tokens secret
- Use environment variables - Don't hardcode credentials
- Rotate tokens regularly - Create new tokens periodically
- Limit token scope - Use team-specific tokens when possible
- Monitor API usage - Watch for suspicious activity
Error Handling
Common Errors
404 Not Found:
{
"error": "Person not found"
}422 Validation Error:
{
"error": "Validation failed",
"errors": [
"First name can't be blank",
"Email is invalid"
]
}429 Rate Limit:
{
"error": "Rate limit exceeded",
"message": "Too many requests for context 'PUT.people'. Please retry after 3600 seconds.",
"retry_after": 3600
}Error Handling Example
async function createPerson(data) {
try {
const response = await axios.post(`${API_URL}/people`, data, {
headers: { Authorization: `Bearer ${API_TOKEN}` }
});
return response.data;
} catch (error) {
if (error.response) {
switch (error.response.status) {
case 422:
console.error('Validation errors:', error.response.data.errors);
break;
case 429:
const retryAfter = error.response.data.retry_after;
console.error(`Rate limited. Retry after ${retryAfter} seconds`);
break;
case 401:
console.error('Invalid API token');
break;
default:
console.error('API error:', error.response.data.error);
}
} else {
console.error('Network error:', error.message);
}
throw error;
}
}Next Steps
- Learn about Events API to track contact interactions
- Set up Webhooks for real-time contact updates
- Explore Custom Fields to extend person data
- Check Tasks API to create follow-ups
Need Help?
- API Reference: See full People endpoints in sidebar
- Support: [email protected]
- Examples: Check our GitHub examples (coming soon)
Updated 9 days ago
