> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sequenzy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> Track subscriber actions and trigger automations with events

# Events

Events represent actions or occurrences in your application that are associated with a subscriber. They're the foundation for behavioral automation and analytics.

## What Are Events?

Events are timestamped records of something that happened:

```json theme={null}
{
  "email": "user@example.com",
  "event": "purchase_completed",
  "properties": {
    "orderId": "order_12345",
    "amount": 99.99,
    "product": "Pro Plan",
    "currency": "USD"
  }
}
```

Unlike tags (which represent current state), events represent **what happened** and **when**.

## Events vs Tags

| Aspect   | Events                      | Tags                      |
| -------- | --------------------------- | ------------------------- |
| Purpose  | Track occurrences           | Categorize subscribers    |
| Multiple | Can have many of same event | Only one instance per tag |
| Time     | Timestamped                 | No timestamp              |
| Data     | Can carry properties        | No additional data        |
| Use case | "User purchased 3 times"    | "User is a customer"      |

**Use events when:**

* The action can happen multiple times
* You need to track when it happened
* You want to attach properties/metadata
* You're building analytics

**Use tags when:**

* You're categorizing subscribers
* You need to segment for campaigns
* You want simple presence/absence logic

## Built-in Events

Sequenzy recognizes these built-in event types:

### SaaS Events

| Event                  | Description                                |
| ---------------------- | ------------------------------------------ |
| `saas.purchase`        | Customer made a purchase                   |
| `saas.payment_failed`  | Payment attempt failed                     |
| `saas.cancelled`       | Subscription cancelled                     |
| `saas.churn`           | Customer churned (end of cancelled period) |
| `saas.refund`          | Refund processed                           |
| `saas.upgrade`         | Plan upgraded                              |
| `saas.downgrade`       | Plan downgraded                            |
| `saas.trial_started`   | Trial period started                       |
| `saas.trial_ended`     | Trial period ended                         |
| `saas.trial_cancelled` | Trial was cancelled before paid conversion |

### Contact Events

| Event                  | Description                      |
| ---------------------- | -------------------------------- |
| `contact.subscribed`   | Subscribed to communications     |
| `contact.unsubscribed` | Unsubscribed from communications |

### Email Events

| Event           | Description             |
| --------------- | ----------------------- |
| `email.opened`  | Opened an email         |
| `email.clicked` | Clicked a link in email |
| `email.replied` | Replied to an email     |
| `email.bounced` | Email bounced           |

### Commerce Events

| Event                                  | Description                                      |
| -------------------------------------- | ------------------------------------------------ |
| `ecommerce.order_placed`               | Customer placed an order                         |
| `ecommerce.order_cancelled`            | Order was cancelled                              |
| `ecommerce.order_fulfilled`            | Order was fulfilled                              |
| `ecommerce.order_shipped`              | A shipment left the warehouse                    |
| `ecommerce.order_out_for_delivery`     | A shipment is out for delivery                   |
| `ecommerce.order_delivered`            | A shipment was delivered                         |
| `ecommerce.delivery_failed`            | A delivery attempt failed                        |
| `ecommerce.order_refunded`             | Refund was created                               |
| `ecommerce.price_drop`                 | Price dropped on a recently viewed product       |
| `ecommerce.cart_abandoned`             | Cart sat inactive with no checkout or order      |
| `ecommerce.browse_abandoned`           | Viewed a product but didn't buy or add to cart   |
| `ecommerce.collection_viewed`          | Known customer viewed a store collection         |
| `ecommerce.search_submitted`           | Known customer searched the store                |
| `ecommerce.customer_created`           | Store customer was created                       |
| `ecommerce.checkout_started`           | Checkout started                                 |
| `ecommerce.replenishment_due`          | A product-specific replenishment reminder is due |
| `ecommerce.reorder_window_missed`      | Customer passed their predicted next-order date  |
| `ecommerce.churn_risk_elevated`        | Predicted churn risk crossed the at-risk level   |
| `ecommerce.back_in_stock_requested`    | Customer requested a back-in-stock notification  |
| `ecommerce.back_in_stock`              | Requested product or variant returned to stock   |
| `ecommerce.back_in_stock_out_of_stock` | Requested product or variant went out of stock   |

<Note>Built-in events automatically apply sync rules when triggered.</Note>

`ecommerce.reorder_window_missed` and `ecommerce.churn_risk_elevated` are
emitted automatically by Sequenzy's nightly
[predictive analytics](/concepts/predictive-analytics) job - you don't send
them yourself. Use them as sequence triggers for winback and at-risk
automations.

## Custom Events

Create your own events for any action in your application:

```bash theme={null}
curl -X POST "https://api.sequenzy.com/api/v1/subscribers/events" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "event": "feature_used",
    "properties": {
      "feature": "export",
      "format": "csv",
      "rowCount": 1500
    }
  }'
```

### Common Custom Events

**Product engagement:**

* `feature_used`
* `project_created`
* `file_uploaded`
* `report_generated`

**User lifecycle:**

* `onboarding_completed`
* `first_value_moment`
* `invited_team_member`

**E-commerce:**

* `product_viewed`
* `cart_started`
* `cart_cleared`
* `checkout_started`
* `review_submitted`

**Content:**

* `article_read`
* `video_watched`
* `course_completed`

## Event Properties

Properties are key-value data attached to events:

```json theme={null}
{
  "event": "order_placed",
  "properties": {
    "orderId": "ord_abc123",
    "total": 149.99,
    "currency": "USD",
    "items": ["Product A", "Product B"],
    "couponUsed": "SAVE20",
    "isFirstOrder": true
  }
}
```

### Property Types

Properties can be:

* **Strings**: `"product": "Pro Plan"`
* **Numbers**: `"amount": 99.99`
* **Booleans**: `"isFirstPurchase": true`
* **Arrays**: `"tags": ["new", "featured"]`
* **Objects**: `"metadata": { "source": "web" }`

### Using Properties in Sequences

Properties can be accessed in sequence conditions and personalization:

```
Condition: event.properties.amount > 100
Action: Send "high-value-purchase" email
```

For email personalization, use `event.` merge tags inside sequence emails:

* `{{event.amount}}`
* `{{event.product}}`
* `{{event.order.id}}`

Sequenzy stores the event snapshot on the sequence run when the subscriber enters the automation. That lets you reference the same event properties in the first, second, or third email without copying them onto the subscriber profile.

When you edit an email inside an event-triggered sequence, the editor preview and test sends fill `event.` merge tags with values from the most recent matching event, so you see what a live send would render. You can override any value in the preview data panel before sending a test.

### Commerce Product Matching

Commerce automations use explicit product IDs from event properties. If you trigger commerce events manually, include these fields so Sequenzy can match replenishment and back-in-stock sequences correctly.

For order events, send product data in `lineItems`:

```json theme={null}
{
  "event": "ecommerce.order_placed",
  "properties": {
    "orderId": "ord_123",
    "orderedAt": "2026-04-02T00:00:00.000Z",
    "lineItems": [
      {
        "provider": "shopify",
        "providerProductId": "788032119674292922",
        "providerVariantId": "45123456789123",
        "title": "Protein Powder",
        "variantTitle": "Vanilla",
        "quantity": 1,
        "priceCents": 8850
      }
    ]
  }
}
```

For product-triggered events such as `ecommerce.replenishment_due`, `ecommerce.back_in_stock`, or `ecommerce.back_in_stock_out_of_stock`, include product fields at the top level or inside `product`:

```json theme={null}
{
  "event": "ecommerce.back_in_stock",
  "properties": {
    "provider": "shopify",
    "providerProductId": "788032119674292922",
    "providerVariantId": "45123456789123",
    "product": {
      "providerId": "788032119674292922",
      "providerVariantId": "45123456789123",
      "title": "Protein Powder",
      "variantTitle": "Vanilla",
      "imageUrl": "https://cdn.example.com/product.png",
      "url": "https://store.example.com/products/protein-powder"
    }
  }
}
```

Sequenzy checks:

* `provider` - usually `shopify` or `woocommerce`
* `providerProductId` or `product.providerId`
* `providerVariantId` or `product.providerVariantId` when exact variant matching is needed
* `lineItems[].providerProductId` on purchase events
* `lineItems[].providerVariantId` on purchase events when variant matching is needed

## Triggering Events

### Single Event

```bash theme={null}
curl -X POST "https://api.sequenzy.com/api/v1/subscribers/events" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "event": "purchase_completed",
    "properties": {
      "orderId": "order_123",
      "amount": 99.99
    }
  }'
```

### Multiple Events (Bulk)

```bash theme={null}
curl -X POST "https://api.sequenzy.com/api/v1/subscribers/events/bulk" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "events": [
      {
        "event": "page_viewed",
        "properties": { "page": "/pricing" }
      },
      {
        "event": "feature_used",
        "properties": { "feature": "calculator" }
      }
    ]
  }'
```

### Auto-Creation

When you trigger an event:

1. **Subscriber** is created if they don't exist
2. **Event definition** is created if it's new
3. **Sync rules** are applied (tags added/removed)
4. **Automations** are triggered if matching

## Dashboard Visibility

In **Settings → Events**, Sequenzy now shows:

* How many unique contacts received each event in the last 24 hours
* Which active sequences currently trigger from that event
* Which paused sequences would trigger if you reactivate them

This makes it easier to verify that your event naming is correct and to spot when an event is feeding multiple automations.

## Events and Sync Rules

Events can automatically modify tags through sync rules:

```
Event: saas.purchase
  → Add tags: "customer"
  → Remove tags: "lead", "trial", "past-due"
```

<Card title="Configure Sync Rules" icon="rotate" href="/concepts/sync-rules">
  Set up automatic tagging based on events
</Card>

## Events in Sequences

### Trigger: Event Received

Start a sequence when an event occurs:

```
Trigger: event_received "purchase_completed"
    │
    ▼
┌─────────────────┐
│ Thank You Email │
└─────────────────┘
    │
    ▼
┌─────────────────┐
│ Wait 3 days     │
└─────────────────┘
    │
    ▼
┌─────────────────┐
│ Feedback Email  │
└─────────────────┘
```

### Wait For Event

Pause execution until an event occurs. The wait has one outgoing path: when the timeout expires the contact either continues down that same path or exits the sequence. To send different emails to contacts who triggered the event and contacts who timed out, follow the wait with a Condition.

```
┌─────────────────────┐
│ Send Onboarding     │
│ Email #1            │
└─────────────────────┘
    │
    ▼
┌──────────────────────┐
│ Wait for Event:      │
│ "onboarding_done"    │
│ Timeout: 7 days      │
│ On timeout: continue │
└──────────────────────┘
    │  event received OR timed out
    ▼
┌──────────────────────┐
│ Condition:           │
│ event_received       │
│ "onboarding_done"    │
└──────────────────────┘
    │
    ├── Yes ─────────────────┐
    │                        │
    ▼                        ▼
┌─────────────┐      ┌─────────────┐
│ Send Tips   │      │ Send Help   │
│ Email       │      │ Email       │
└─────────────┘      └─────────────┘
```

See [Wait for Event](/concepts/sequences) for timeout actions and the property-matching limits.

### Condition: Check Event Properties

Branch based on event data:

```
┌─────────────────────────┐
│ Condition:              │
│ event.properties.amount │
│ > 500                   │
└─────────────────────────┘
         │
    ┌────┴────┐
    │         │
   Yes        No
    │         │
    ▼         ▼
┌─────────┐ ┌─────────┐
│ VIP     │ │ Standard│
│ Email   │ │ Email   │
└─────────┘ └─────────┘
```

## Integration Examples

### E-commerce Purchase

```javascript theme={null}
// After successful payment
await fetch("https://api.sequenzy.com/api/v1/subscribers/events", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email: order.customerEmail,
    event: "saas.purchase",
    properties: {
      orderId: order.id,
      amount: order.total,
      currency: order.currency,
      products: order.items.map((i) => i.name),
      isFirstOrder: customer.orderCount === 1,
    },
    customAttributes: {
      lastOrderDate: new Date().toISOString(),
      totalSpent: customer.totalSpent,
    },
  }),
});
```

### Feature Activation

```javascript theme={null}
// When user completes onboarding
await fetch("https://api.sequenzy.com/api/v1/subscribers/events", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email: user.email,
    event: "onboarding_completed",
    properties: {
      completedSteps: ["profile", "integration", "first-project"],
      timeToComplete: "2 days",
    },
  }),
});
```

### Subscription Lifecycle

```javascript theme={null}
// Stripe webhook handler
switch (event.type) {
  case "customer.subscription.created":
    await triggerEvent(email, "saas.purchase", {
      plan: subscription.plan.nickname,
      amount: subscription.plan.amount / 100,
      interval: subscription.plan.interval,
    });
    break;

  case "customer.subscription.deleted":
    await triggerEvent(email, "saas.cancelled", {
      reason: subscription.cancellation_details?.reason,
      feedback: subscription.cancellation_details?.feedback,
    });
    break;

  case "invoice.payment_failed":
    await triggerEvent(email, "saas.payment_failed", {
      invoiceId: invoice.id,
      attemptCount: invoice.attempt_count,
    });
    break;
}
```

## Event Analytics

Events are stored and available for analysis:

* **Event counts**: How many times an event occurred
* **Time series**: Events over time
* **Subscriber timeline**: All events for a subscriber
* **Funnel analysis**: Conversion between events

## Best Practices

### 1. Use Consistent Naming

```
✓ "order.placed", "order.shipped", "order.delivered"
✓ "feature.used", "feature.activated"

✗ "order_placed", "OrderShipped", "order-delivered"
```

### 2. Include Relevant Properties

```
✓ Event: "purchase_completed"
  Properties: { orderId, amount, products, isFirstOrder }

✗ Event: "purchase_completed"
  Properties: {} (missing context)
```

### 3. Don't Over-Event

Track meaningful actions, not every click:

```
✓ "checkout_started", "checkout_completed"
✗ "button_clicked", "page_scrolled" (too granular)
```

### 4. Use Events for Analytics, Tags for Segmentation

```
✓ Event: "feature_used" (track usage patterns)
  Tag: "power-user" (segment for campaigns)

✗ Tag: "used-feature-jan", "used-feature-feb" (tag per occurrence)
```

## Related

<CardGroup cols={2}>
  <Card title="Tags" icon="tags" href="/concepts/tags">
    Use tags with events for segmentation
  </Card>

  <Card title="Sync Rules" icon="rotate" href="/concepts/sync-rules">
    Auto-tag based on events
  </Card>

  <Card title="Sequences" icon="diagram-project" href="/concepts/sequences">
    Trigger automations with events
  </Card>

  <Card title="Events API" icon="code" href="/api-reference/subscribers/events/trigger">
    Trigger events via API
  </Card>
</CardGroup>
