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_idto 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
| Field | Type | Description |
|---|---|---|
event_name | string | Name of the event (e.g., "user_signup", "purchase_completed") |
Optional Fields
| Field | Type | Description |
|---|---|---|
user_info | object | User/contact information for the event |
user_info.contact_external_id | string | Contact's external ID |
user_info.email | string | Contact's email address |
user_info.phone | string | Contact's phone number |
user_info.name | string | Contact's full name |
user_info.custom_fields | object | Additional contact fields |
source | object | Event source information |
source.type | string | Source type (e.g., "web_signup", "api", "webhook") |
source.ip | string | IP address of the source |
source.user_agent | string | User agent string |
event_data | object | Custom event payload data |
variables | object | Template variables for workflow execution |
trigger_at | string | ISO 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)
| Field | Type | Description |
|---|---|---|
success | boolean | Always true for successful event queue |
trigger_id | string | UUID of the created trigger (use this to track execution) |
job_id | string | Queue job ID |
message | string | Human-readable status message |
scheduled_for | string | ISO timestamp (only if trigger_at was provided) |
Error Response (4xx)
{
"statusCode": 400,
"message": "Error description",
"error": "Bad Request"
}
Common Error Responses
| Status Code | Error Message | Cause | Solution |
|---|---|---|---|
| 400 | Event name is required | Missing event_name field | Provide event_name in request body |
| 400 | Invalid trigger_at format | Malformed timestamp | Use ISO 8601 format (e.g., 2024-12-25T10:00:00Z) |
| 400 | trigger_at must be a future date | Past timestamp provided | Use future date/time |
| 401 | Unauthorized | Invalid or missing API key | Check X-API-Key header |
| 401 | Invalid team context | Missing or invalid X-Team-ID | Provide valid X-Team-ID header |
| 404 | Event type not found | Event not configured | Create 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 registrationapi- API integrationwebhook- Webhook triggermobile_app- Mobile app eventadmin_panel- Manual trigger from admincron- 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:
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:
- Finds Active Workflows - Searches for workflows configured to listen to this event name
- Applies Filters - Checks workflow conditions (tags, segments, cooldowns)
- Queues Execution - Creates workflow executions for matching workflows
- Processes Steps - Each workflow step is queued to the appropriate channel processor
- Tracks Progress - Updates trigger status as workflows execute
Event Matching Example
If you have these workflows:
- Welcome Email - Listens to
user_signupevent - Onboarding Series - Listens to
user_signupevent (with tag filter: "new_users") - Purchase Thank You - Listens to
purchase_completedevent
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) |
| Processing | Async (background worker) | Sync (immediate) |
| Returns | trigger_id + job_id | Full execution results |
| Use Case | Production (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
- Trigger API V2 - Track event execution status
- Workflows Overview - Learn about workflow configuration
- Trigger Workflow - Alternative workflow trigger method
- API Overview - General API documentation
Related Endpoints
POST /api/v1/events/trigger- Synchronous event trigger (not recommended for production)POST /api/v1/workflows/trigger- Direct workflow triggerGET /api/v1/triggers/:id- Get trigger execution statusGET /api/v1/triggers/:id/workflow- Get detailed workflow execution info