Events API

Fire custom named events against contacts to trigger behavior-driven automations. This is the most flexible way to connect your application's business logic to EmailSendX's automation engine.

Overview

The Events API lets you send named events from your application to EmailSendX. When an event is fired for a contact, EmailSendX checks all active automations in the workspace for ones that have a Custom Event trigger configured with a matching event name. All matching automations are triggered immediately for that contact.

This creates a direct bridge between your application's business events (checkout completed, trial started, invoice paid) and targeted email workflows in EmailSendX.

Typical event-to-automation flow:

  1. User completes checkout in your app
  2. Your backend calls POST /contacts/{id}/events with name: "purchase_completed"
  3. EmailSendX matches all active automations with trigger CUSTOM_EVENT: purchase_completed
  4. Matching automations start running for the contact — sending welcome emails, onboarding sequences, etc.

Fire an Event

POST/api/v1/contacts/{id}/eventsscope: contacts:write

Fire a named custom event for a contact. Returns the count of automations that were triggered by the event.

Parameters

NameTypeInRequiredDescription
idstringpathrequiredThe contact ID to fire the event for
namestringbodyrequiredEvent name. Case-insensitive match against automation trigger configuration.
dataobjectbodyoptionalFree-form JSON data payload attached to this event. Available in automation conditional steps.

Request Body

json
{
  "name": "purchase_completed",
  "data": {
    "orderId": "ord_abc123",
    "amount": 99.00,
    "currency": "USD",
    "items": ["Pro Plan - Annual"],
    "coupon": "LAUNCH20"
  }
}

Response

json
{
  "data": {
    "contactId": "clx1a2b3c4d5e6f7g8h9i0j",
    "eventName": "purchase_completed",
    "matchingAutomations": 2,
    "firedAt": "2026-04-22T09:15:30Z"
  }
}

Automation Matching

When an event is fired, EmailSendX finds all automations in the workspace where:

  • The automation's trigger type is CUSTOM_EVENT
  • The trigger's configured event name matches the fired event name (case-insensitive)
  • The automation's status is active

All matching automations are triggered in parallel. The matchingAutomations field in the response tells you how many were triggered.

Case-insensitive matching

Event names are matched case-insensitively. purchase_completed, Purchase_Completed, and PURCHASE_COMPLETED all match an automation configured with the event name purchase_completed. Use a consistent naming convention for clarity.
bash
# Response when 0 automations matched
{
  "data": {
    "contactId": "clx1a2b3c4d5e6f7g8h9i0j",
    "eventName": "trial_started",
    "matchingAutomations": 0,
    "firedAt": "2026-04-22T09:16:00Z"
  }
}
# Note: matchingAutomations: 0 is not an error.
# It means no active automations are configured for this event name.

Data Payload

The optional data field lets you pass arbitrary JSON to the automation runner. This data is available within automation conditional steps, allowing you to branch logic based on event properties.

For example, a purchase_completed event with data.amount could branch the automation to send different emails based on purchase value.

Data payload limits:

  • Maximum payload size: 16 KB
  • Must be a valid JSON object (not an array or primitive)
  • Nested objects and arrays are supported

Complete Example: Purchase Flow

A realistic backend integration that upserts a contact, fires a purchase event, and enrolls them in a post-purchase automation:

const API_KEY = process.env.EMAILSENDX_API_KEY;
const BASE = 'https://emailsendx.com/api/v1';

async function handleCheckoutCompleted(order) {
  const headers = {
    'Authorization': `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  };

  // 1. Upsert the contact
  const upsertRes = await fetch(`${BASE}/contacts`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      email: order.customerEmail,
      firstName: order.customerFirstName,
      metadata: {
        plan: order.planName,
        customerId: order.stripeCustomerId,
      },
    }),
  });
  const { data: contact } = await upsertRes.json();

  // 2. Fire the purchase_completed event
  const eventRes = await fetch(`${BASE}/contacts/${contact.id}/events`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      name: 'purchase_completed',
      data: {
        orderId: order.id,
        amount: order.totalAmount,
        currency: order.currency,
        items: order.lineItems.map(i => i.name),
      },
    }),
  });

  const { data: event } = await eventRes.json();
  console.log(`Triggered ${event.matchingAutomations} automation(s)`);
}

Events powering your automations?

Set up CUSTOM_EVENT automations in the dashboard to respond to every event your backend fires.