Skip to main content

Send Event (Async)

Queue events for asynchronous workflow processing. This lightweight API creates a trigger, queues the event, and returns immediately with tracking IDs.

Endpoint

POST /api/v1/events/send

Headers

X-API-Key: sk_live_your_api_key
X-Team-ID: your-team-id
Content-Type: application/json

Why Use This Endpoint?

  • 🚀 Lightweight & Fast - Returns immediately, no waiting for processing
  • ⚡ Async Processing - Worker handles event matching and workflow execution in background
  • 📊 Built-in Tracking - Get trigger_id to monitor execution status
  • 🎯 Flexible Events - Trigger any configured workflows that match the event
  • 🔄 Queue-Based - Reliable event processing with automatic retries
  • 📈 Scalable - Handle high-volume event streams without blocking

Core Concept

This endpoint queues an event for asynchronous processing. The API returns immediately with a trigger_id, while workers process the event in the background.

Event processing flow:

API Request → Create Trigger → Queue Event → Return trigger_id

Worker → Match Workflows → Execute → Track Results

Request Structure

Required Fields

FieldTypeDescription
event_namestringName of the event (e.g., "user_signup", "purchase_completed")

Optional Fields

FieldTypeDescription
user_infoobjectUser/contact information for the event
user_info.contact_external_idstringContact's external ID
user_info.emailstringContact's email address
user_info.phonestringContact's phone number
user_info.namestringContact's full name
user_info.custom_fieldsobjectAdditional contact fields
sourceobjectEvent source information
source.typestringSource type (e.g., "web_signup", "api", "webhook")
source.ipstringIP address of the source
source.user_agentstringUser agent string
event_dataobjectCustom event payload data
variablesobjectTemplate variables for workflow execution
trigger_atstringISO 8601 timestamp for scheduled execution

Use Case Examples

Example 1: User Signup Event

Trigger welcome workflows when a user signs up.

curl -X POST https://api.sendmator.com/api/v1/events/send \
-H "X-API-Key: sk_live_your_api_key" \
-H "X-Team-ID: your-team-id" \
-H "Content-Type: application/json" \
-d '{
"event_name": "user_signup",
"user_info": {
"contact_external_id": "user_12345",
"email": "john.doe@example.com",
"name": "John Doe"
},
"source": {
"type": "web_signup",
"ip": "192.168.1.1"
},
"event_data": {
"signup_method": "google_oauth",
"referral_code": "FRIEND2024"
}
}'

Response:

{
"success": true,
"trigger_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"job_id": "12345",
"message": "Event queued successfully"
}

Example 2: Purchase Completed Event

Send order confirmation and follow-up sequences.

curl -X POST https://api.sendmator.com/api/v1/events/send \
-H "X-API-Key: sk_live_your_api_key" \
-H "X-Team-ID: your-team-id" \
-H "Content-Type: application/json" \
-d '{
"event_name": "purchase_completed",
"user_info": {
"contact_external_id": "user_67890",
"email": "alice@example.com",
"name": "Alice Johnson"
},
"event_data": {
"order_id": "ORD-98765",
"amount": 149.99,
"currency": "USD",
"items_count": 3
},
"variables": {
"order_total": "$149.99",
"estimated_delivery": "2024-12-20",
"tracking_url": "https://track.example.com/ORD-98765"
}
}'

Example 3: Password Reset Request

Trigger password reset workflow with OTP codes.

curl -X POST https://api.sendmator.com/api/v1/events/send \
-H "X-API-Key: sk_live_your_api_key" \
-H "X-Team-ID: your-team-id" \
-H "Content-Type: application/json" \
-d '{
"event_name": "password_reset_requested",
"user_info": {
"contact_external_id": "user_11111",
"email": "bob@example.com"
},
"source": {
"type": "web_app",
"ip": "203.0.113.45"
},
"variables": {
"reset_code": "ABC123",
"reset_link": "https://app.example.com/reset?token=xyz789",
"expiry_time": "30 minutes"
}
}'

Example 4: Scheduled Event

Queue an event to be processed at a specific time.

curl -X POST https://api.sendmator.com/api/v1/events/send \
-H "X-API-Key: sk_live_your_api_key" \
-H "X-Team-ID: your-team-id" \
-H "Content-Type: application/json" \
-d '{
"event_name": "subscription_renewal_reminder",
"user_info": {
"contact_external_id": "user_22222",
"email": "customer@example.com"
},
"trigger_at": "2024-12-15T10:00:00Z",
"variables": {
"subscription_type": "Premium",
"renewal_date": "2024-12-20",
"amount": "$29.99"
}
}'

Response:

{
"success": true,
"trigger_id": "a1b2c3d4-e5f6-7890-a1b2-c3d4e5f67890",
"job_id": "67890",
"message": "Event scheduled for 2024-12-15T10:00:00.000Z",
"scheduled_for": "2024-12-15T10:00:00.000Z"
}

Example 5: Custom Event with Rich Data

Send custom events with complex data structures.

curl -X POST https://api.sendmator.com/api/v1/events/send \
-H "X-API-Key: sk_live_your_api_key" \
-H "X-Team-ID: your-team-id" \
-H "Content-Type: application/json" \
-d '{
"event_name": "course_completed",
"user_info": {
"contact_external_id": "student_456",
"email": "learner@example.com",
"name": "Sarah Lee"
},
"event_data": {
"course_id": "CS101",
"course_name": "Introduction to Programming",
"completion_date": "2024-12-10",
"score": 95,
"certificate_url": "https://certs.example.com/CS101-456"
},
"variables": {
"course_title": "Introduction to Programming",
"student_name": "Sarah Lee",
"grade": "A",
"certificate_link": "https://certs.example.com/CS101-456",
"next_course": "Advanced Programming"
}
}'

Response Fields

Success Response (201 Created)

FieldTypeDescription
successbooleanAlways true for successful event queue
trigger_idstringUUID of the created trigger (use this to track execution)
job_idstringQueue job ID
messagestringHuman-readable status message
scheduled_forstringISO timestamp (only if trigger_at was provided)

Error Response (4xx)

{
"statusCode": 400,
"message": "Error description",
"error": "Bad Request"
}

Common Error Responses

Status CodeError MessageCauseSolution
400Event name is requiredMissing event_name fieldProvide event_name in request body
400Invalid trigger_at formatMalformed timestampUse ISO 8601 format (e.g., 2024-12-25T10:00:00Z)
400trigger_at must be a future datePast timestamp providedUse future date/time
401UnauthorizedInvalid or missing API keyCheck X-API-Key header
401Invalid team contextMissing or invalid X-Team-IDProvide valid X-Team-ID header
404Event type not foundEvent not configuredCreate event type in dashboard first

Event Data Structure

User Info Object

Contains contact/user information:

{
"user_info": {
"contact_external_id": "user_123", // Your system's user ID
"email": "user@example.com",
"phone": "+1234567890",
"name": "John Doe",
"custom_fields": {
"company": "Acme Inc",
"role": "Admin",
"plan": "Enterprise"
}
}
}

Source Object

Tracks where the event originated:

{
"source": {
"type": "web_signup", // Event source type
"ip": "192.168.1.1", // IP address
"user_agent": "Mozilla/5.0..." // Browser/client info
}
}

Common source.type values:

  • web_signup - Website registration
  • api - API integration
  • webhook - Webhook trigger
  • mobile_app - Mobile app event
  • admin_panel - Manual trigger from admin
  • cron - Scheduled/automated event

Event Data Object

Custom event-specific data:

{
"event_data": {
// Any custom fields relevant to your event
"order_id": "ORD-123",
"amount": 99.99,
"product_name": "Premium Plan",
"quantity": 1
}
}

Variables Object

Template variables for workflow execution:

{
"variables": {
"user_name": "John",
"product_name": "Premium Subscription",
"discount_code": "WELCOME20",
"support_email": "help@example.com"
}
}

Variables are available in all workflow templates using Handlebars syntax:

Hello {{user_name}},

Welcome to {{product_name}}! Use code {{discount_code}} for 20% off.

Tracking Event Execution

After sending an event, track its execution status using the returned trigger_id.

Step 1: Get Basic Trigger Info

GET /api/v1/triggers/{trigger_id}

Response:

{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"flow_type": "workflow",
"trigger_type": "workflow",
"status": "completed",
"created_at": "2024-12-10T10:00:00.000Z",
"started_at": "2024-12-10T10:00:01.000Z",
"completed_at": "2024-12-10T10:05:30.000Z",
"summary": {
"total_contacts": 1000,
"sent": 995,
"failed": 5,
"filtered": 0
},
"details_endpoint": "/triggers/f47ac10b-58cc-4372-a567-0e02b2c3d479/workflow"
}

Step 2: Get Detailed Workflow Info

GET /api/v1/triggers/{trigger_id}/workflow

See Trigger API V2 Documentation for complete response structure.

How Events Match Workflows

When you send an event, the system:

  1. Finds Active Workflows - Searches for workflows configured to listen to this event name
  2. Applies Filters - Checks workflow conditions (tags, segments, cooldowns)
  3. Queues Execution - Creates workflow executions for matching workflows
  4. Processes Steps - Each workflow step is queued to the appropriate channel processor
  5. Tracks Progress - Updates trigger status as workflows execute

Event Matching Example

If you have these workflows:

  • Welcome Email - Listens to user_signup event
  • Onboarding Series - Listens to user_signup event (with tag filter: "new_users")
  • Purchase Thank You - Listens to purchase_completed event

Sending user_signup event will trigger:

  • ✅ Welcome Email (always)
  • ✅ Onboarding Series (only if contact has "new_users" tag)
  • ❌ Purchase Thank You (different event)

Best Practices

1. Use Consistent Event Names

// ✅ Good: Clear, descriptive, snake_case
"event_name": "user_signup"
"event_name": "purchase_completed"
"event_name": "subscription_cancelled"

// ❌ Bad: Inconsistent naming
"event_name": "UserSignup"
"event_name": "purchase-completed"
"event_name": "cancel_sub"

2. Always Include Contact Identifier

{
"event_name": "user_activity",
"user_info": {
"contact_external_id": "user_123" // ✅ Required for contact matching
}
}

3. Structure Event Data Logically

{
"event_name": "order_shipped",
"user_info": {
"contact_external_id": "user_123"
},
"event_data": {
// Order-specific data
"order_id": "ORD-456",
"shipping_carrier": "FedEx",
"tracking_number": "1Z999AA10123456784"
},
"variables": {
// Template-ready variables
"order_number": "#456",
"tracking_link": "https://fedex.com/track/1Z999AA10123456784",
"estimated_delivery": "Dec 25, 2024"
}
}

4. Track Important Events

async function sendEvent(eventName, userData, eventData) {
try {
const response = await fetch('/api/v1/events/send', {
method: 'POST',
headers: {
'X-API-Key': process.env.SENDMATOR_API_KEY,
'X-Team-ID': process.env.SENDMATOR_TEAM_ID,
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_name: eventName,
user_info: userData,
event_data: eventData
})
});

const data = await response.json();

if (!response.ok) {
throw new Error(data.message);
}

// ✅ Store trigger_id for later tracking
await db.events.create({
trigger_id: data.trigger_id,
event_name: eventName,
user_id: userData.contact_external_id,
created_at: new Date()
});

return data.trigger_id;

} catch (error) {
console.error('Failed to send event:', error);
throw error;
}
}

5. Handle Scheduled Events

// Schedule event for future execution
const scheduledTime = new Date('2024-12-25T10:00:00Z');

if (scheduledTime < new Date()) {
throw new Error('Cannot schedule events in the past');
}

await sendEvent({
event_name: 'holiday_greeting',
user_info: { contact_external_id: 'user_123' },
trigger_at: scheduledTime.toISOString()
});

6. Error Handling

async function sendEventWithRetry(eventData, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('/api/v1/events/send', {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'X-Team-ID': TEAM_ID,
'Content-Type': 'application/json'
},
body: JSON.stringify(eventData)
});

const data = await response.json();

if (!response.ok) {
// Don't retry on client errors (400-499)
if (response.status >= 400 && response.status < 500) {
throw new Error(`Client error: ${data.message}`);
}
throw new Error(`Server error: ${data.message}`);
}

console.log(`Event sent successfully: ${data.trigger_id}`);
return data;

} catch (error) {
console.error(`Attempt ${attempt} failed:`, error);

if (attempt === maxRetries) {
throw new Error(`Failed after ${maxRetries} attempts: ${error.message}`);
}

// Exponential backoff
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
}
}
}

Integration Examples

Node.js/Express

const express = require('express');
const app = express();

app.post('/users/signup', async (req, res) => {
const { email, name } = req.body;

// Create user in your database
const user = await db.users.create({ email, name });

// Send event to trigger welcome workflows
await fetch('https://api.sendmator.com/api/v1/events/send', {
method: 'POST',
headers: {
'X-API-Key': process.env.SENDMATOR_API_KEY,
'X-Team-ID': process.env.SENDMATOR_TEAM_ID,
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_name: 'user_signup',
user_info: {
contact_external_id: user.id,
email: user.email,
name: user.name
},
source: {
type: 'web_signup',
ip: req.ip
}
})
});

res.json({ success: true, userId: user.id });
});

Python/Django

import requests
from django.conf import settings

def send_event(event_name, user_info, event_data=None):
"""Send event to Sendmator"""
response = requests.post(
'https://api.sendmator.com/api/v1/events/send',
headers={
'X-API-Key': settings.SENDMATOR_API_KEY,
'X-Team-ID': settings.SENDMATOR_TEAM_ID,
'Content-Type': 'application/json'
},
json={
'event_name': event_name,
'user_info': user_info,
'event_data': event_data or {}
}
)
response.raise_for_status()
return response.json()

# Usage in view
def user_signup_view(request):
user = User.objects.create(
email=request.POST['email'],
name=request.POST['name']
)

# Trigger welcome workflows
send_event(
event_name='user_signup',
user_info={
'contact_external_id': str(user.id),
'email': user.email,
'name': user.name
}
)

return JsonResponse({'success': True})

PHP/Laravel

use Illuminate\Support\Facades\Http;

function sendEvent($eventName, $userInfo, $eventData = []) {
$response = Http::withHeaders([
'X-API-Key' => config('sendmator.api_key'),
'X-Team-ID' => config('sendmator.team_id'),
])->post('https://api.sendmator.com/api/v1/events/send', [
'event_name' => $eventName,
'user_info' => $userInfo,
'event_data' => $eventData,
]);

return $response->json();
}

// Usage in controller
public function signup(Request $request) {
$user = User::create([
'email' => $request->email,
'name' => $request->name,
]);

// Trigger welcome workflows
sendEvent('user_signup', [
'contact_external_id' => $user->id,
'email' => $user->email,
'name' => $user->name,
]);

return response()->json(['success' => true]);
}

Rate Limits

This endpoint is subject to rate limiting based on your account plan:

  • Starter: 1,000 requests per hour
  • Pro: 10,000 requests per hour
  • Enterprise: Custom limits

Exceeding limits returns 429 Too Many Requests with retry-after header.

Comparison: /events/send vs /events/trigger

Feature/events/send (Async)/events/trigger (Sync)
Response Time⚡ Instant (~50ms)🐌 Slow (waits for processing)
ProcessingAsync (background worker)Sync (immediate)
Returnstrigger_id + job_idFull execution results
Use CaseProduction (high volume)Testing/debugging
Recommended✅ Yes⚠️ Only for testing

Recommendation: Use /events/send for production. It's faster, more scalable, and provides better error handling.

Next Steps

  • POST /api/v1/events/trigger - Synchronous event trigger (not recommended for production)
  • POST /api/v1/workflows/trigger - Direct workflow trigger
  • GET /api/v1/triggers/:id - Get trigger execution status
  • GET /api/v1/triggers/:id/workflow - Get detailed workflow execution info