Events API

The Events API allows you to track user events and behaviors in your SMASHSEND account. Events are powerful tools for triggering automated workflows, segmenting contacts, and understanding user engagement patterns. This API is commonly used to track product usage, user actions, and custom business events.

What are Events?

Events represent actions or occurrences in your application (e.g., “user.signup”, “purchase.completed”, “video.watched”). Each event is associated with a contact via email and can include custom properties to capture relevant details.

Authentication & Base URL

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:

• Single events: 1,000 requests per minute
• Batch events: 50 requests per minute (up to 10,000 events/min)
• Recommended: Use batch endpoints for high-volume tracking

Events Endpoints

POST/v1/events

Track a single event for a contact. This endpoint automatically creates or updates the contact if they don't exist, and enqueues the event for processing.

Request Body Parameters

event - Event name (required). Must contain only alphanumeric characters, underscores, hyphens, dots, and colons. Max 60 characters.

identify - User identification object (required)
  • identify.email - Contact email address (required)
  • identify.traits - Contact attributes/properties to sync (optional)

properties - Event properties object (optional). Can contain any key-value pairs with event-specific data.

timestamp - Event timestamp as ISO string or Unix timestamp (optional). Defaults to current time. Must be within ±30 years.

messageId - Custom message ID for deduplication (optional). If not provided, SMASHSEND generates one automatically. Max 128 characters.

Property Limits

• Max 100 leaf keys per event
• Max nesting depth: 3 levels
• Max string length: 1,000 characters
• Max array length: 100 items
• Max payload size: 32KB per event
• Arrays can only contain primitive values (no nested objects)

Code Examples

Install the SDK: npm install smashsend-node

import { SMASHSEND } from 'smashsend-node';

const smashsend = new SMASHSEND({
  apiKey: 'sk_live_abc123...'
});

// Basic event tracking
const response = await smashsend.events.send({
  event: 'user.signup',
  identify: {
    email: 'user@example.com'
  },
  properties: {
    plan: 'premium',
    source: 'website',
    referrer: 'google'
  }
});

console.log(`Event sent with ID: ${response.messageId}`);

// Event with contact traits sync
await smashsend.events.send({
  event: 'purchase.completed',
  identify: {
    email: 'customer@example.com',
    traits: {
      firstName: 'John',
      lastName: 'Doe',
      company: 'ACME Corp',
      isCustomer: true
    }
  },
  properties: {
    orderId: 'order_12345',
    amount: 99.99,
    currency: 'USD',
    items: ['product_1', 'product_2']
  }
});

// Event with custom messageId for deduplication
await smashsend.events.send({
  event: 'subscription.renewed',
  identify: { email: 'user@example.com' },
  properties: { subscriptionId: 'sub_xyz' },
  messageId: 'renewal_2024_01_15_sub_xyz'
});

// Event with custom timestamp
await smashsend.events.send({
  event: 'video.watched',
  identify: { email: 'viewer@example.com' },
  properties: {
    videoId: 'vid_123',
    duration: 325,
    completed: true
  },
  timestamp: '2024-01-15T10:30:00Z'
});

Response

{
  "success": true,
  "messageId": "msg_abc123xyz789",
  "info": "Event queued for processing"
}

POST/v1/events/batch

Send multiple events in a single batch operation. This is the recommended endpoint for high-volume event tracking as it's more efficient and has higher rate limits.

Batch Processing Benefits

• Process up to 200 events per request
• Reduced network overhead and faster throughput
• Automatic deduplication handling
• Partial success support (some events can succeed while others fail)
• Up to 10,000 events per minute (50 requests × 200 events)

Request Body Parameters

events - Array of event objects (required). Each event follows the same schema as the single event endpoint. Max 200 events per batch. Max payload size: 6.4MB.

Code Examples

import { SMASHSEND } from 'smashsend-node';

const smashsend = new SMASHSEND({
  apiKey: 'sk_live_abc123...'
});

// Track multiple events at once
const events = [
  {
    event: 'page.view',
    identify: { email: 'user1@example.com' },
    properties: { page: '/home', referrer: 'google' }
  },
  {
    event: 'button.click',
    identify: { email: 'user2@example.com' },
    properties: { button: 'cta', location: 'hero' }
  },
  {
    event: 'form.submitted',
    identify: {
      email: 'user3@example.com',
      traits: {
        firstName: 'Jane',
        lastName: 'Smith'
      }
    },
    properties: { formId: 'contact_us', fields: 5 }
  }
];

const result = await smashsend.events.sendBatch(events);

console.log(`Accepted: ${result.accepted}, Failed: ${result.failed}`);
console.log(`Duplicates: ${result.duplicated}`);

// Handle errors for failed events
if (result.errors && result.errors.length > 0) {
  result.errors.forEach(error => {
    console.error(`Event at index ${error.index} failed:`);
    error.errors.forEach(err => {
      console.error(`  - [${err.code}] ${err.message}`);
    });
  });
}

// Check successful events
if (result.events) {
  result.events.forEach(event => {
    console.log(`Event ${event.index}: ${event.messageId} (${event.status})`);
  });
}

Response

The batch endpoint returns different HTTP status codes based on the outcome:
200 - All events processed successfully
207 - Partial success (some events succeeded, others failed)
400 - All events failed

{
  "accepted": 3,
  "failed": 0,
  "duplicated": 0,
  "events": [
    {
      "index": 0,
      "messageId": "msg_abc123",
      "status": "accepted"
    },
    {
      "index": 1,
      "messageId": "msg_def456",
      "status": "accepted"
    },
    {
      "index": 2,
      "messageId": "msg_ghi789",
      "status": "accepted"
    }
  ],
  "errors": []
}

Partial Success Response

{
  "accepted": 2,
  "failed": 1,
  "duplicated": 0,
  "events": [
    {
      "index": 0,
      "messageId": "msg_abc123",
      "status": "accepted"
    },
    {
      "index": 2,
      "messageId": "msg_ghi789",
      "status": "accepted"
    }
  ],
  "errors": [
    {
      "index": 1,
      "errors": [
        {
          "code": "INVALID_EMAIL",
          "message": "Invalid email format"
        }
      ]
    }
  ]
}

Event Naming Best Practices

Event names should be descriptive, consistent, and follow a clear naming convention. We recommend using a hierarchical structure with dots to separate namespaces.

Recommended Format

object.action or category.object.action

Examples

// User events
user.signup
user.login
user.logout
user.profile_updated
user.password_changed

// E-commerce events
product.viewed
product.added_to_cart
product.removed_from_cart
cart.checkout_started
purchase.completed
purchase.refunded

// Content events
article.viewed
article.shared
video.played
video.completed
pdf.downloaded

// SaaS events
trial.started
subscription.activated
subscription.upgraded
subscription.cancelled
feature.used
workspace.created

// Engagement events
email.opened
email.clicked
form.submitted
button.clicked
page.viewed
search.performed

Naming Constraints

• Max length: 60 characters
• Allowed characters: alphanumeric, underscores, hyphens, dots, colons
• Case-sensitive: “User.Signup” and “user.signup” are different events
• Be consistent: Choose either snake_case or camelCase and stick with it

Event Deduplication

SMASHSEND automatically handles event deduplication to prevent duplicate events from being processed. This is especially useful for handling network retries or idempotent operations.

Automatic Deduplication

If you don't provide a messageId, SMASHSEND generates one automatically based on the event content. The system tracks events for 24 hours to detect duplicates.

Custom Message IDs

For precise control over deduplication, provide your own messageId. This is useful when you have a unique identifier from your system that you want to use.

// Use order ID for deduplication
await smashsend.events.send({
  event: 'purchase.completed',
  identify: { email: 'customer@example.com' },
  properties: {
    orderId: 'order_12345',
    amount: 99.99
  },
  messageId: 'purchase_order_12345' // Ensures this purchase is tracked once
});

// Use subscription ID + date for renewals
await smashsend.events.send({
  event: 'subscription.renewed',
  identify: { email: 'user@example.com' },
  properties: {
    subscriptionId: 'sub_xyz',
    period: '2024-01'
  },
  messageId: 'renewal_2024_01_sub_xyz'
});

How it works: When a duplicate event is detected, it's marked as “duplicate” in batch responses and counted in the duplicated field. The event is not processed again, but the API call succeeds.

Contact Traits Synchronization

Events can automatically update contact information using the identify.traits field. This allows you to keep contact data in sync while tracking events, eliminating the need for separate contact update calls.

How Traits Work

• If the contact doesn't exist, they're created with the provided traits
• If the contact exists, their properties are updated/merged with the traits
• Traits follow the same schema as contact properties
• Standard fields (firstName, lastName, etc.) and custom fields are supported

// Create contact and track event simultaneously
await smashsend.events.send({
  event: 'user.signup',
  identify: {
    email: 'newuser@example.com',
    traits: {
      firstName: 'John',
      lastName: 'Doe',
      company: 'ACME Corp',
      phone: '+1234567890',
      plan: 'premium',
      signupSource: 'landing_page'
    }
  },
  properties: {
    referrer: 'google',
    campaignId: 'summer_2024'
  }
});

// Update contact info while tracking engagement
await smashsend.events.send({
  event: 'profile.completed',
  identify: {
    email: 'user@example.com',
    traits: {
      avatarUrl: 'https://example.com/avatar.jpg',
      countryCode: 'US',
      timezone: 'America/New_York',
      isProfileComplete: true
    }
  }
});

// Track purchase and update customer status
await smashsend.events.send({
  event: 'purchase.completed',
  identify: {
    email: 'customer@example.com',
    traits: {
      isCustomer: true,
      lastPurchaseDate: '2024-01-15',
      lifetimeValue: 499.99,
      customerTier: 'gold'
    }
  },
  properties: {
    orderId: 'order_12345',
    amount: 99.99
  }
});

Note: Contact traits are optional. If you only want to track the event without updating contact data, omit the traits field or pass an empty object.

Error Handling

The Events API uses standard HTTP status codes and returns detailed error information to help you debug issues.

Common Error Responses

400 - Bad Request

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Event name can only contain alphanumeric characters, underscores, hyphens, dots, and colons"
}

401 - Unauthorized

{
  "statusCode": 401,
  "error": "Unauthorized",
  "message": "Invalid API key"
}

413 - Payload Too Large

{
  "statusCode": 413,
  "error": "Payload Too Large",
  "message": "Event payload exceeds 32KB limit"
}

429 - Rate Limit Exceeded

{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "Rate limit exceeded. Please retry after 60 seconds."
}

Validation Errors

// Invalid email format
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "\"identify.email\" must be a valid email"
}

// Event name too long
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Event name cannot exceed 60 characters"
}

// Properties too deep
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Properties exceed maximum depth of 3"
}

// Too many events in batch
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Batch cannot exceed 200 events"
}

Common Use Cases

1. Product Analytics & User Behavior Tracking

// Track feature usage
await smashsend.events.send({
  event: 'feature.used',
  identify: { email: 'user@example.com' },
  properties: {
    featureName: 'advanced_search',
    duration: 45,
    resultsCount: 12
  }
});

// Track user journey
await smashsend.events.send({
  event: 'onboarding.step_completed',
  identify: { email: 'newuser@example.com' },
  properties: {
    step: 3,
    stepName: 'connect_integration',
    totalSteps: 5
  }
});

2. E-commerce & Transaction Tracking

// Track shopping cart events
const cartEvents = [
  {
    event: 'product.added_to_cart',
    identify: { email: 'shopper@example.com' },
    properties: {
      productId: 'prod_123',
      productName: 'Widget Pro',
      price: 49.99,
      quantity: 2
    }
  },
  {
    event: 'cart.checkout_started',
    identify: { email: 'shopper@example.com' },
    properties: {
      cartTotal: 99.98,
      itemCount: 2
    }
  },
  {
    event: 'purchase.completed',
    identify: {
      email: 'shopper@example.com',
      traits: {
        isCustomer: true,
        lastPurchaseDate: new Date().toISOString()
      }
    },
    properties: {
      orderId: 'order_789',
      amount: 99.98,
      currency: 'USD',
      paymentMethod: 'credit_card'
    }
  }
];

await smashsend.events.sendBatch(cartEvents);

3. Content Engagement Tracking

// Track blog engagement
await smashsend.events.send({
  event: 'article.viewed',
  identify: { email: 'reader@example.com' },
  properties: {
    articleId: 'blog_post_42',
    title: 'Getting Started with Events API',
    category: 'tutorials',
    readTime: 8
  }
});

// Track video engagement
await smashsend.events.send({
  event: 'video.completed',
  identify: { email: 'viewer@example.com' },
  properties: {
    videoId: 'vid_123',
    title: 'Product Demo',
    duration: 325,
    percentageWatched: 95
  }
});

4. SaaS Subscription Lifecycle

// Track trial and subscription events
const subscriptionEvents = [
  {
    event: 'trial.started',
    identify: {
      email: 'prospect@example.com',
      traits: {
        firstName: 'Jane',
        company: 'Startup Inc',
        trialEndsAt: '2024-02-01'
      }
    },
    properties: {
      trialDays: 14,
      plan: 'premium'
    }
  },
  {
    event: 'subscription.activated',
    identify: {
      email: 'prospect@example.com',
      traits: {
        isCustomer: true,
        plan: 'premium',
        subscriptionStatus: 'active'
      }
    },
    properties: {
      planId: 'plan_premium_monthly',
      amount: 99.00,
      billingPeriod: 'monthly'
    }
  }
];

await smashsend.events.sendBatch(subscriptionEvents);

5. Workflow Automation Triggers

Events can trigger automated workflows in SMASHSEND. For example, you can create a workflow that sends a welcome email when a “user.signup” event is received, or a post-purchase follow-up when a “purchase.completed” event occurs.

// Trigger welcome email workflow
await smashsend.events.send({
  event: 'user.signup',
  identify: {
    email: 'newuser@example.com',
    traits: {
      firstName: 'John',
      signupDate: new Date().toISOString()
    }
  }
});

// Trigger abandoned cart workflow
await smashsend.events.send({
  event: 'cart.abandoned',
  identify: { email: 'shopper@example.com' },
  properties: {
    cartValue: 249.99,
    itemCount: 3,
    items: ['product_1', 'product_2', 'product_3']
  }
});

// Trigger re-engagement workflow
await smashsend.events.send({
  event: 'user.inactive_30_days',
  identify: { email: 'dormant@example.com' },
  properties: {
    lastActiveDate: '2023-12-15',
    daysSinceActive: 30
  }
});

Best Practices

1. Use Batch Endpoints for High Volume

When tracking multiple events, always use the batch endpoint. It reduces network overhead, has higher rate limits, and is more efficient.

2. Implement Proper Error Handling

Always handle errors gracefully and implement retry logic with exponential backoff for transient failures. Use the messageId for idempotent retries.

3. Keep Event Names Consistent

Document your event naming convention and enforce it across your team. Inconsistent event names make analytics and automation difficult.

4. Include Relevant Context in Properties

Add enough context to understand what happened without looking at other data sources. Include IDs, timestamps, and relevant metadata.

5. Sync Contact Data with Traits

Use the identify.traits field to keep contact information up-to-date. This eliminates the need for separate contact update calls.

6. Monitor Your Event Volume

Keep track of your event volume to stay within rate limits. If you need higher limits, contact support to discuss your use case.

7. Use Custom Message IDs for Deduplication

For critical events (like purchases or subscriptions), provide a custom messageId based on your unique identifier to ensure proper deduplication.

8. Test Your Events

Before deploying to production, test your events in a development environment. Verify that event names, properties, and traits are correct.

Limits & Constraints Reference

Event Limits

• Event name: max 60 characters
• Message ID: max 128 characters
• Event payload: max 32KB
• Timestamp range: ±30 years from current time

Property Limits

• Max leaf keys: 100
• Max nesting depth: 3 levels
• Max string length: 1,000 characters
• Max array length: 100 items
• Arrays can only contain primitive values

Batch Limits

• Max events per batch: 200
• Batch payload: max 6.4MB

Rate Limits

• Single events: 1,000 requests/minute
• Batch events: 50 requests/minute
• Max events via batch: 10,000/minute (50 × 200)