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:

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=5551234 matches (555) 123-4567, 555-123-4567, +1-555-123-4567
  • Formatting characters (dashes, parentheses, spaces) are ignored
  • Partial matches supported - 555 will 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 email
  • home - Personal email
  • other - Other email

Email Status

  • active - Valid, can receive emails
  • bounced - Email bounced, invalid
  • unsubscribed - User unsubscribed

Phone Types

  • mobile - Mobile/cell phone
  • work - Work phone
  • home - Home phone
  • other - Other phone

Phone Status

  • active - Valid, can receive calls/texts
  • disconnected - Phone number no longer valid
  • do-not-call - User requested no calls

Address Types

  • home - Home address
  • work - Work address
  • other - 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 qualified
  • Qualified - Lead is qualified
  • Proposal - Proposal sent
  • Negotiation - In negotiation
  • Closed Won - Deal closed successfully
  • Closed 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

  1. Always provide primary contact method - Mark at least one email/phone as primary
  2. Validate email formats - Use regex or validation library before submitting
  3. Normalize phone numbers - Use consistent format (E.164 recommended)
  4. Clean up duplicates - Leverage deduplication by email
  5. Keep data current - Regularly update contact information

Performance

  1. Use pagination - Don't fetch all contacts at once
  2. Batch operations - Group updates when possible
  3. Cache frequently accessed data - Reduce API calls
  4. Use webhooks - Get real-time updates instead of polling
  5. Implement rate limiting - Respect API rate limits

Tagging Strategy

  1. Use consistent naming - Lowercase with hyphens (e.g., "hot-lead")
  2. Create tag taxonomy - Organize tags by category
  3. Don't over-tag - Keep tags focused and meaningful
  4. Clean up old tags - Remove outdated or unused tags
  5. Document tag meanings - Maintain a tag glossary

Security

  1. Never expose API tokens - Keep tokens secret
  2. Use environment variables - Don't hardcode credentials
  3. Rotate tokens regularly - Create new tokens periodically
  4. Limit token scope - Use team-specific tokens when possible
  5. 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

Need Help?