Events API Guide

Events API Guide

The Events API allows you to track all interactions and activities with your contacts. Events are the foundation of engagement tracking in Sure Send CRM, capturing everything from page views to form submissions to property searches.

Overview

Events represent actions or interactions that occur with your contacts. They help you:

  • Build engagement timelines
  • Track website activity
  • Monitor property interest
  • Measure campaign effectiveness
  • Trigger automations based on behavior

Common Event Types:

  • page_view - Website page viewed
  • property_view - Property listing viewed
  • saved_property - Property saved to favorites
  • form_submission - Contact form submitted
  • search - Property search performed
  • inquiry - Direct inquiry submitted
  • email_opened - Email campaign opened
  • email_clicked - Email link clicked
  • appointment_scheduled - Appointment booked
  • document_downloaded - Document downloaded

Creating Events

Basic Event

Endpoint: POST /api/partner/events

curl -X POST https://api.suresend.ai/api/partner/events \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "page_view",
    "personId": "person-uuid",
    "pageUrl": "https://example.com/about",
    "pageTitle": "About Us"
  }'

Response:

{
  "id": "event-uuid",
  "personId": "person-uuid",
  "eventType": "page_view",
  "occurredAt": "2025-10-16T12:00:00Z",
  "pageUrl": "https://example.com/about",
  "pageTitle": "About Us",
  "createdAt": "2025-10-16T12:00:00Z"
}

Page View Event

Track when contacts visit pages on your website:

curl -X POST https://api.suresend.ai/api/partner/events \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "page_view",
    "personId": "person-uuid",
    "pageUrl": "https://example.com/properties/123",
    "pageTitle": "Beautiful 3BR Home",
    "pageDuration": 45,
    "pageReferrer": "https://google.com/search",
    "ipAddress": "192.168.1.1",
    "userAgent": "Mozilla/5.0..."
  }'

Property View Event

Track interest in specific properties (real estate):

curl -X POST https://api.suresend.ai/api/partner/events \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "property_view",
    "personId": "person-uuid",
    "message": "Viewed 3-bedroom home in Portland",
    "property": {
      "id": "prop-123",
      "address": "123 Main St, Portland, OR 97201",
      "price": 500000,
      "beds": 3,
      "baths": 2,
      "sqft": 1800,
      "propertyType": "house",
      "listingUrl": "https://example.com/properties/123"
    }
  }'

Saved Property Event

Track when contacts save properties to their favorites or saved lists:

curl -X POST https://api.suresend.ai/api/partner/events \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "saved_property",
    "personId": "person-uuid",
    "message": "Saved property to favorites",
    "description": "Saved 3-bedroom home to favorites list",
    "property": {
      "id": "prop-456",
      "address": "456 Oak Ave, Portland, OR 97202",
      "price": 650000,
      "beds": 3,
      "baths": 2.5,
      "sqft": 2100,
      "propertyType": "house",
      "listingUrl": "https://example.com/properties/456",
      "savedToList": "Favorites"
    },
    "metadata": {
      "savedFrom": "search results",
      "deviceType": "mobile",
      "interestLevel": "very-high",
      "action": "saved_to_favorites"
    }
  }'

Property Data Fields:

  • savedToList - Name of the saved list (e.g., "Favorites", "Shortlist", "Must See")

Metadata Fields:

  • savedFrom - Where the property was saved from (e.g., "search results", "property detail page", "agent recommendation")
  • deviceType - Device used to save the property
  • interestLevel - Indicates high engagement (e.g., "very-high")
  • action - Specific action taken (e.g., "saved_to_favorites", "added_to_shortlist")

Property Search Event

Track search behavior and preferences:

curl -X POST https://api.suresend.ai/api/partner/events \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "search",
    "personId": "person-uuid",
    "message": "Searched for homes in Portland",
    "propertySearch": {
      "minPrice": 300000,
      "maxPrice": 500000,
      "beds": 3,
      "baths": 2,
      "location": "Portland, OR",
      "propertyType": "house",
      "keywords": "modern kitchen, garage"
    }
  }'

Form Submission Event

Track form submissions with contact creation:

curl -X POST https://api.suresend.ai/api/partner/events \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "form_submission",
    "person": {
      "firstName": "John",
      "lastName": "Doe",
      "emails": [{"value": "[email protected]", "isPrimary": true}],
      "phones": [{"value": "+1-555-1234", "isPrimary": true}]
    },
    "message": "Contact form submitted",
    "description": "User requested more information about properties",
    "metadata": {
      "formName": "Contact Us",
      "formId": "contact-form-1",
      "interests": ["buying", "3-bedroom"],
      "budget": "300k-500k"
    }
  }'

Response includes person:

{
  "event": { ... },
  "person": {
    "id": "person-uuid",
    "firstName": "John",
    "lastName": "Doe",
    ...
  },
  "created": true  // true if new person created, false if existing
}

Email Campaign Event

Track email engagement:

curl -X POST https://api.suresend.ai/api/partner/events \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "email_opened",
    "personId": "person-uuid",
    "message": "Opened Spring 2025 campaign email",
    "campaign": {
      "name": "Spring 2025 Listings",
      "id": "campaign-123",
      "source": "mailchimp",
      "medium": "email"
    }
  }'

Person Matching

When creating events, you can associate them with people in three ways:

1. Use Existing Person ID

If you already know the person ID:

{
  "type": "page_view",
  "personId": "existing-person-uuid",
  "pageUrl": "https://example.com/page"
}

2. Match Existing Person by Email/Phone

Provide person data, and the system will find the matching contact:

{
  "type": "page_view",
  "person": {
    "emails": [{"value": "[email protected]"}]
  },
  "pageUrl": "https://example.com/page"
}

3. Create New Person Automatically

If no match is found, a new person is created:

{
  "type": "form_submission",
  "person": {
    "firstName": "New",
    "lastName": "Lead",
    "emails": [{"value": "[email protected]", "isPrimary": true}],
    "phones": [{"value": "+1-555-1234", "isPrimary": true}],
    "tags": ["website-lead"]
  },
  "message": "New lead from website"
}

Company Association

When creating events, you can optionally associate a company with the person. This is useful for:

  • B2B lead tracking where contacts represent businesses
  • Linking form submissions to company accounts
  • Automatically associating people with their employers
  • Tracking company-level engagement

How Company Association Works

  1. Find by ID: If you provide a company id, the system looks up that specific company
  2. Find by Name: If no ID, the system searches for an existing company by name (case-insensitive)
  3. Create if Not Found: If no match is found and name is provided, a new company is created
  4. Automatic Person Association: When a company is found or created, the person is automatically linked to that company

Company Parameter Structure

{
  "company": {
    "id": "uuid (optional - use to link to existing company)",
    "name": "string (required if no id)",
    "website": "string",
    "industry": "string",
    "companySize": "string",
    "description": "string",
    "annualRevenue": 5000000,
    "registrationNumber": "string",
    "taxId": "string",
    "primaryEmail": "string",
    "primaryPhone": "string",
    "emails": [
      { "value": "[email protected]", "type": "work", "isPrimary": true }
    ],
    "phones": [
      { "value": "+1-555-1234", "type": "main", "isPrimary": true }
    ],
    "addresses": [
      {
        "street": "123 Business St",
        "city": "San Francisco",
        "state": "CA",
        "code": "94105",
        "country": "US",
        "type": "headquarters",
        "isPrimary": true
      }
    ],
    "tags": ["enterprise", "tech-sector"],
    "customFields": {
      "accountTier": "Gold"
    }
  }
}

Response with Company

When a company is included in the request, the response includes the company object and a creation flag:

{
  "person": { ... },
  "event": { ... },
  "company": {
    "id": "company-uuid",
    "name": "Acme Corporation",
    "website": "https://acme.com",
    "industry": "Technology",
    "companySize": "51-200",
    "description": "Leading provider of innovative solutions",
    "emails": [
      { "value": "[email protected]", "type": "work", "isPrimary": true, "status": "active" }
    ],
    "phones": [
      { "value": "+1-555-1234", "type": "main", "isPrimary": true, "status": "active" }
    ],
    "addresses": [
      {
        "street": "123 Business St",
        "city": "San Francisco",
        "state": "CA",
        "code": "94105",
        "country": "US",
        "type": "headquarters",
        "isPrimary": true
      }
    ],
    "tags": ["enterprise"],
    "created": "2025-10-22T12:00:00Z",
    "updated": "2025-10-22T12:00:00Z"
  },
  "wasPersonCreated": true,
  "wasCompanyCreated": true
}

HTTP Status Codes

The response status code indicates what was created:

  • 201 Created: A new person OR company was created
  • 200 OK: Both person and company already existed (matched existing records)

Example: Form Submission with Company

curl -X POST https://api.suresend.ai/api/partner/events \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "form_submission",
    "person": {
      "firstName": "Jane",
      "lastName": "Smith",
      "emails": [{"value": "[email protected]", "isPrimary": true}],
      "phones": [{"value": "+1-555-2345", "isPrimary": true}]
    },
    "company": {
      "name": "Acme Corporation",
      "website": "https://acmecorp.com",
      "industry": "Technology",
      "companySize": "51-200"
    },
    "message": "Demo request submitted",
    "metadata": {
      "formName": "Demo Request",
      "productInterest": "Enterprise Plan"
    }
  }'

Example: Link to Existing Company by ID

curl -X POST https://api.suresend.ai/api/partner/events \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "inquiry",
    "person": {
      "firstName": "Bob",
      "lastName": "Johnson",
      "emails": [{"value": "[email protected]"}]
    },
    "company": {
      "id": "existing-company-uuid"
    },
    "message": "Sales inquiry from existing account"
  }'

Company Deduplication

The system uses case-insensitive name matching to prevent duplicate companies:

  • "Acme Corporation" matches "acme corporation" and "ACME CORPORATION"
  • Whitespace is trimmed from company names
  • If a match is found, existing company data is updated (non-destructive merge)
  • New emails, phones, addresses, and tags are added without removing existing ones

Person-Company Association

When both person and company are involved:

  • A PersonCompany association is automatically created
  • If the company was newly created, it is set as the person's primary company
  • If the association already exists, no duplicate is created
  • The is_current flag is set to true for new associations

Validation

The company parameter has the following requirements:

  • Company name is required (unless providing an id for lookup)
  • If an id is provided, the company must exist in your team
  • All other fields are optional

Event Data Structure

Core Fields

All events have these base fields:

{
  "type": "page_view",           // Required: Event type
  "personId": "uuid",             // Person ID (use personId OR person)
  "person": {...},                // Person data (use personId OR person)
  "company": {...},               // Company data (optional, see Company Association)
  "occurredAt": "2025-10-16...",  // When event occurred (ISO 8601)
  "message": "Short summary",     // Brief description
  "description": "Long details",  // Detailed description
  "source": "website",            // Event source
  "system": "google_analytics"    // Tracking system
}

Page View Fields

{
  "pageUrl": "https://example.com/page",
  "pageTitle": "Page Title",
  "pageDuration": 45,             // Time on page (seconds)
  "pageReferrer": "https://google.com",
  "ipAddress": "192.168.1.1",
  "userAgent": "Mozilla/5.0..."
}

Property Data

{
  "property": {
    "id": "prop-123",
    "address": "123 Main St",
    "price": 500000,
    "beds": 3,
    "baths": 2,
    "sqft": 1800,
    "propertyType": "house",
    "listingUrl": "https://...",
    // Any custom fields
  }
}

Property Search Data

{
  "propertySearch": {
    "minPrice": 300000,
    "maxPrice": 500000,
    "beds": 3,
    "baths": 2,
    "location": "Portland, OR",
    "propertyType": "house",
    "keywords": "modern, garage"
  }
}

Campaign Data

{
  "campaign": {
    "name": "Spring 2025",
    "id": "campaign-123",
    "source": "facebook",
    "medium": "cpc",
    "term": "portland homes",
    "content": "ad-variant-a"
  }
}

Custom Metadata

The metadata field allows you to store any additional data as flexible key-value pairs. This is perfect for:

  • Form-specific data (form name, form ID, submission details)
  • User preferences and interests
  • Session/tracking information
  • Budget/price preferences
  • Custom attributes specific to your application
  • Integration-specific data

Flexible Structure:

{
  "metadata": {
    "formName": "Contact Form",
    "formId": "contact-form-1",
    "deviceType": "mobile",
    "sessionId": "session-123",
    "interests": ["buying", "3-bedroom", "garage"],
    "budget": "300k-500k",
    "customField": "any value",
    "nestedData": {
      "key": "value",
      "another": "nested value"
    }
  }
}

Benefits:

  • ✅ Store any JSON-serializable data
  • ✅ No schema restrictions
  • ✅ Automatically displayed in CRM activity timeline
  • ✅ Indexed for efficient querying
  • ✅ Supports nested objects and arrays

Limits: To ensure system performance and prevent abuse, metadata has the following reasonable limits:

  • Maximum Size: 256 KB (262,144 bytes)
    • Plenty of space for detailed form data and tracking information
    • Most metadata will be under 5 KB
  • Maximum Keys: 100 keys at root level
    • Sufficient for comprehensive event tracking
    • Nested objects can have additional keys
  • Maximum Depth: 10 levels of nesting
    • Prevents overly complex structures
    • More than enough for any legitimate use case

Example of Acceptable Metadata:

{
  "formData": {
    "personalInfo": {
      "name": "John Doe",
      "email": "[email protected]",
      "preferences": {
        "budget": "300k-500k",
        "bedrooms": 3,
        "locations": ["Charleston", "Mount Pleasant"]
      }
    }
  },
  "tracking": {
    "referrer": "google.com",
    "sessionId": "abc123",
    "deviceType": "mobile"
  },
  "engagement": {
    "timeOnPage": 120,
    "scrollDepth": 85,
    "clicks": ["cta-button", "property-card"]
  }
}

This example is well within limits (< 1 KB, 15 keys, 4 levels deep).

Retrieving Events

List All Events

Endpoint: GET /api/partner/events

curl "https://api.suresend.ai/api/partner/events?limit=50" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Query Parameters:

  • personId - Filter by person
  • eventType - Filter by event type
  • source - Filter by source
  • limit - Max events to return (max: 1000)

Response:

[
  {
    "id": "event-uuid",
    "personId": "person-uuid",
    "eventType": "page_view",
    "occurredAt": "2025-10-16T12:00:00Z",
    "pageUrl": "https://example.com/page",
    "metadata": {
      "formName": "Contact Us",
      "interests": ["buying"]
    },
    "createdAt": "2025-10-16T12:00:00Z"
  }
]

Note: The metadata field is included in responses when present on the event.

Filter Events by Person

curl "https://api.suresend.ai/api/partner/events?personId=person-uuid&limit=100" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Filter Events by Type

curl "https://api.suresend.ai/api/partner/events?eventType=property_view&limit=100" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Get Specific Event

Endpoint: GET /api/partner/events/{id}

curl https://api.suresend.ai/api/partner/events/event-uuid \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Updating Events

Endpoint: PUT /api/partner/events/{id}

curl -X PUT https://api.suresend.ai/api/partner/events/event-uuid \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Updated description",
    "metadata": {
      "additionalField": "new value"
    }
  }'

Deleting Events

Endpoint: DELETE /api/partner/events/{id}

curl -X DELETE https://api.suresend.ai/api/partner/events/event-uuid \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Common Use Cases

1. Track Website Activity

// Website tracking script
async function trackPageView(email, pageUrl, pageTitle) {
  await fetch('https://api.suresend.ai/api/partner/events', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_TOKEN}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      type: 'page_view',
      person: {
        emails: [{ value: email }]
      },
      pageUrl,
      pageTitle,
      pageDuration: Math.round((Date.now() - pageLoadTime) / 1000),
      pageReferrer: document.referrer,
      userAgent: navigator.userAgent
    })
  });
}

2. Track Form Submissions

// Form handler
async function handleFormSubmit(formData) {
  const response = await axios.post(
    'https://api.suresend.ai/api/partner/events',
    {
      type: 'form_submission',
      person: {
        firstName: formData.firstName,
        lastName: formData.lastName,
        emails: [{ value: formData.email, isPrimary: true }],
        phones: [{ value: formData.phone, type: 'mobile', isPrimary: true }]
      },
      message: 'Contact form submitted',
      metadata: {
        formName: 'Contact Us',
        interests: formData.interests,
        message: formData.message
      },
      source: 'website',
      pageUrl: window.location.href
    },
    {
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    }
  );

  const { person, created } = response.data;
  console.log(created ? 'New lead created' : 'Existing contact updated');
}

3. Build Engagement Timeline

async function getContactTimeline(personId) {
  const events = await axios.get(
    `https://api.suresend.ai/api/partner/events`,
    {
      params: { personId, limit: 100 },
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    }
  );

  // Group by type
  const timeline = events.data.reduce((acc, event) => {
    if (!acc[event.eventType]) acc[event.eventType] = [];
    acc[event.eventType].push(event);
    return acc;
  }, {});

  return timeline;
}

// Usage
const timeline = await getContactTimeline('person-uuid');
console.log(`Page views: ${timeline.page_view?.length || 0}`);
console.log(`Property views: ${timeline.property_view?.length || 0}`);
console.log(`Searches: ${timeline.search?.length || 0}`);

4. Track Property Interest

async function trackPropertyView(personId, property) {
  await axios.post(
    'https://api.suresend.ai/api/partner/events',
    {
      type: 'property_view',
      personId,
      message: `Viewed ${property.beds}BR home at ${property.address}`,
      property: {
        id: property.id,
        address: property.address,
        price: property.price,
        beds: property.beds,
        baths: property.baths,
        sqft: property.sqft,
        listingUrl: property.url
      },
      pageUrl: window.location.href,
      source: 'website'
    },
    {
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    }
  );

  // Auto-tag based on price range
  if (property.price > 1000000) {
    await applyTag(personId, 'luxury-buyer');
  }
}

// Track when properties are saved to favorites
async function trackSavedProperty(personId, property, savedFrom) {
  await axios.post(
    'https://api.suresend.ai/api/partner/events',
    {
      type: 'saved_property',
      personId,
      message: `Saved property to favorites`,
      description: `Saved ${property.beds}BR home at ${property.address}`,
      property: {
        id: property.id,
        address: property.address,
        price: property.price,
        beds: property.beds,
        baths: property.baths,
        sqft: property.sqft,
        propertyType: property.type,
        listingUrl: property.url,
        savedToList: 'Favorites'
      },
      metadata: {
        savedFrom: savedFrom, // 'search results', 'property detail page', etc.
        deviceType: /mobile/i.test(navigator.userAgent) ? 'mobile' : 'desktop',
        interestLevel: 'very-high',
        action: 'saved_to_favorites'
      },
      source: 'website'
    },
    {
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    }
  );

  // Auto-tag high-intent leads
  await applyTag(personId, 'high-intent-buyer');
}

5. Analyze Search Behavior

async function analyzeSearchBehavior(personId) {
  const events = await axios.get(
    `https://api.suresend.ai/api/partner/events`,
    {
      params: { personId, eventType: 'search', limit: 100 },
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    }
  );

  const searches = events.data;

  // Analyze price range preferences
  const priceRanges = searches.map(s => ({
    min: s.propertySearch?.minPrice || 0,
    max: s.propertySearch?.maxPrice || Infinity
  }));

  const avgMinPrice = priceRanges.reduce((sum, r) => sum + r.min, 0) / priceRanges.length;
  const avgMaxPrice = priceRanges.reduce((sum, r) => sum + r.max, 0) / priceRanges.length;

  // Analyze location preferences
  const locations = searches
    .map(s => s.propertySearch?.location)
    .filter(Boolean);

  const topLocations = [...new Set(locations)]
    .map(loc => ({
      location: loc,
      count: locations.filter(l => l === loc).length
    }))
    .sort((a, b) => b.count - a.count);

  return {
    averagePriceRange: { min: avgMinPrice, max: avgMaxPrice },
    topLocations,
    totalSearches: searches.length
  };
}

6. Custom Metadata Tracking

Track rich form data and user preferences:

async function trackContactFormSubmission(formData) {
  await axios.post(
    'https://api.suresend.ai/api/partner/events',
    {
      type: 'form_submission',
      person: {
        firstName: formData.firstName,
        lastName: formData.lastName,
        emails: [{ value: formData.email, isPrimary: true }],
        phones: [{ value: formData.phone, isPrimary: true }]
      },
      message: `${formData.formName} submission`,
      description: formData.message,
      metadata: {
        // Form identification
        formName: formData.formName,
        formId: formData.formId,
        formVersion: '2.0',

        // User preferences
        interests: formData.interests, // ['buying', '3-bedroom', 'garage']
        budget: formData.budget, // '300k-500k'
        timeframe: formData.timeframe, // 'within-3-months'

        // Additional context
        pageUrl: window.location.href,
        referringSource: document.referrer,
        sessionId: getSessionId(),
        deviceType: isMobile() ? 'mobile' : 'desktop',

        // Custom business data
        marketingConsent: formData.marketingConsent,
        preferredContactMethod: formData.preferredContactMethod,
        bestTimeToCall: formData.bestTimeToCall
      },
      source: 'website',
      occurredAt: new Date().toISOString()
    },
    {
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    }
  );
}

Benefits:

  • All form data is preserved in the event
  • Displays nicely in the CRM activity timeline
  • Can be used for filtering and reporting
  • No schema limitations

7. Email Campaign Tracking

// Track email opens
async function trackEmailOpen(personId, campaignId) {
  await axios.post(
    'https://api.suresend.ai/api/partner/events',
    {
      type: 'email_opened',
      personId,
      message: 'Opened marketing email',
      campaign: {
        id: campaignId,
        name: 'Spring 2025 Campaign',
        source: 'mailchimp',
        medium: 'email'
      },
      source: 'email_campaign'
    },
    {
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    }
  );
}

// Track link clicks
async function trackEmailClick(personId, campaignId, linkUrl) {
  await axios.post(
    'https://api.suresend.ai/api/partner/events',
    {
      type: 'email_clicked',
      personId,
      message: `Clicked link: ${linkUrl}`,
      campaign: {
        id: campaignId,
        name: 'Spring 2025 Campaign'
      },
      pageUrl: linkUrl,
      source: 'email_campaign'
    },
    {
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    }
  );
}

8. B2B Lead Tracking with Company

Track form submissions from business contacts with company information:

async function trackB2BFormSubmission(formData) {
  const response = await axios.post(
    'https://api.suresend.ai/api/partner/events',
    {
      type: 'form_submission',
      person: {
        firstName: formData.firstName,
        lastName: formData.lastName,
        emails: [{ value: formData.email, isPrimary: true }],
        phones: [{ value: formData.phone, isPrimary: true }]
      },
      company: {
        name: formData.companyName,
        website: formData.companyWebsite,
        industry: formData.industry,
        companySize: formData.companySize
      },
      message: `B2B inquiry from ${formData.companyName}`,
      metadata: {
        formName: 'B2B Contact Form',
        productInterest: formData.productInterest,
        estimatedDealSize: formData.budget
      },
      source: 'website'
    },
    {
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    }
  );

  const { person, company, wasPersonCreated, wasCompanyCreated } = response.data;

  if (wasCompanyCreated) {
    console.log(`New company created: ${company.name}`);
  } else {
    console.log(`Linked to existing company: ${company.name}`);
  }

  if (wasPersonCreated) {
    console.log(`New contact created: ${person.firstName} ${person.lastName}`);
  }
}

Rate Limiting

The Events API has specific rate limits to handle high-volume tracking:

Rate Limit Headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 85
X-RateLimit-Reset: 3600
X-RateLimit-Context: token:POST.events

Best Practices:

  • Batch events when possible
  • Monitor rate limit headers
  • Implement exponential backoff on 429 errors
  • Contact support for higher limits if needed

Best Practices

Event Naming

  1. Use consistent event types - Stick to standard types when possible
  2. Descriptive custom types - Use clear names like property_inquiry not pi
  3. Lowercase with underscores - Follow convention: page_view, form_submission

Data Quality

  1. Always include occurredAt - Track when events actually happened
  2. Provide meaningful messages - Help humans understand the event
  3. Use structured data - Leverage property, propertySearch, campaign fields
  4. Include source/system - Track where events originate

Performance

  1. Async tracking - Don't block user experience waiting for events
  2. Batch when possible - Reduce API calls
  3. Cache person IDs - Avoid repeated person lookups
  4. Handle errors gracefully - Don't fail user actions if tracking fails

Privacy

  1. Respect user consent - Only track if user consents
  2. Anonymize when needed - Don't track PII unnecessarily
  3. Follow regulations - GDPR, CCPA compliance
  4. Provide opt-out - Allow users to stop tracking

Integration Examples

Google Analytics Integration

// Track GA events in CRM
function setupGAIntegration() {
  gtag('event', 'page_view', {
    event_callback: async function(url) {
      if (window.userEmail) {
        await trackPageView(window.userEmail, url, document.title);
      }
    }
  });
}

Segment Integration

// Forward Segment events to CRM
analytics.ready(() => {
  analytics.on('track', async (event, properties) => {
    const user = analytics.user();

    await axios.post(
      'https://api.suresend.ai/api/partner/events',
      {
        type: event.toLowerCase().replace(/ /g, '_'),
        person: {
          emails: [{ value: user.email() }]
        },
        message: event,
        metadata: properties,
        source: 'segment',
        system: 'segment'
      },
      {
        headers: { Authorization: `Bearer ${API_TOKEN}` }
      }
    );
  });
});

Next Steps

Need Help?