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

# Events & triggers

> Understanding events and triggers in the workflow system

A trigger is the foundation of workflow automation in the Thena platform. It consists of two key components: an event and filters. While events represent what happened, triggers allow you to specify exactly when a workflow should execute based on those events.

## Understanding triggers

<CardGroup cols={1}>
  <Card title="Core concept" icon="bolt">
    A trigger is a combination of an event and optional filters. Events tell us what happened (e.g., "ticket created"), while filters let us specify precise conditions about when we care about that event (e.g., "only when the ticket priority is high").
  </Card>
</CardGroup>

## Event types

<CardGroup cols={2}>
  <Card title="System events" icon="gear">
    • Ticket events: Created, updated, status changed <br />
    • User events: Created, updated, permissions changed <br />
    • Team events: Created, members changed <br />
    • Account events: Created, updated, status changed <br />
  </Card>

  <Card title="Integration events" icon="plug">
    • Slack events: Message sent, channel created <br />
    • Email events: Received, sent, bounced <br />
    • Custom app events: Any app-specific events <br />
    • Scheduled events: Time-based triggers <br />
  </Card>
</CardGroup>

## Event anatomy

An event in the Thena Platform consists of several key components that define its structure and behavior.

### Key components

<CardGroup cols={2}>
  <Card title="Core properties" icon="circle-info">
    • **uid**: Unique identifier for the event<br />
    • **eventName**: Human-readable name<br />
    • **eventType**: Machine-readable type (e.g., `ticket:updated`)<br />
    • **source**: Origin of the event<br />
    • **description**: Human-readable description
  </Card>

  <Card title="Schema structure" icon="code">
    • **message**: Core event data including actor and payload<br />
    • **messageAttributes**: Context and metadata about the event<br />
    • **required fields**: Mandatory data points<br />
    • **properties**: Data type definitions and validations
  </Card>
</CardGroup>

### Event data structure

<AccordionGroup>
  <Accordion title="Message object" icon="envelope">
    The core event data container:

    * **actor**: Who triggered the event
    * **orgId**: Organization context
    * **eventId**: Unique event instance ID
    * **payload**: The actual event data
    * **timestamp**: When the event occurred
  </Accordion>

  <Accordion title="Payload" icon="box">
    The main event data:

    * **Current state**: Latest data (e.g., updated ticket)
    * **Previous state**: Data before the change (when applicable)
    * **Required fields**: Mandatory data points
    * **Optional fields**: Additional context
  </Accordion>

  <Accordion title="Message attributes" icon="tags">
    Additional context about the event:

    * **event\_name**: Name of the event
    * **event\_timestamp**: When it occurred
    * **context\_user\_id**: Who triggered it
    * **context\_organization\_id**: Org context
  </Accordion>

  <Accordion title="Metadata" icon="circle-info">
    Configuration for event processing:

    * **entityType**: Type of entity involved
    * **pathToTeamId**: Location of team identifier
    * **pathToAnnotate**: Path for data enrichment
    * **requiredFields**: Fields needed for processing
  </Accordion>
</AccordionGroup>

<Note>
  Events follow a consistent structure that enables:

  * Rich context through nested properties
  * Type safety with JSON schema validation
  * Clear audit trail with actor and timestamp information
  * Flexible data access through dot notation in filters
</Note>

Here's a comprehensive example of a ticket update event:

```json theme={null}
{
  "uid": "D0DN56NJ10C3RJJG1TGR3D86HM0S8",
  "description": "This event is triggered when a ticket is updated",
  "eventName": "Ticket updated",
  "source": "platform_app",
  "eventType": "ticket:updated",
  "schema": {
    "type": "object",
    "required": ["message", "messageAttributes"],
    "properties": {
      "message": {
        "type": "object",
        "required": ["actor", "orgId", "eventId", "payload", "eventType", "timestamp"],
        "properties": {
          "actor": {
            "type": "object",
            "required": ["email", "id", "type"],
            "properties": {
              "id": { "type": "string" },
              "type": { "type": "string" },
              "email": { "type": "string" }
            }
          },
          "payload": {
            "type": "object",
            "required": ["previousTicket", "ticket"],
            "properties": {
              "ticket": {
                "type": "object",
                "required": ["id", "title", "teamId"],
                "properties": {
                  "id": { "type": "string" },
                  "title": { "type": "string" },
                  "teamId": { "type": "string" }
                  // ... additional ticket properties
                }
              },
              "previousTicket": {
                "type": "object",
                "required": ["id", "title", "teamId"]
                // ... same structure as ticket
              }
            }
          }
        }
      },
      "messageAttributes": {
        "type": "object",
        "required": [
          "event_name",
          "event_id",
          "event_timestamp",
          "context_user_id",
          "context_user_type",
          "context_organization_id"
        ]
        // ... attribute properties
      }
    }
  },
  "metadata": {
    "entityType": "Ticket",
    "pathToTeamId": "context.event.message.payload.ticket.teamId",
    "pathToAnnotate": "context.event.message.payload.ticket",
    "requiredFields": {
      "ticketId": "{{context.event.message.payload.ticket.id}}"
    }
  }
}
```

## Trigger components

### Event definition

| Name         | Type     | Options                     | Comments                  |
| :----------- | :------- | :-------------------------- | :------------------------ |
| Event Name   | string   | Required, Format: app:event | Unique event identifier   |
| Event Schema | object   | Required                    | JSON Schema of event data |
| Event Data   | object   | Required                    | Actual event payload      |
| Source       | string   | Required                    | Event origin identifier   |
| Timestamp    | datetime | Required                    | Event occurrence time     |

### Filter operators

Filters in triggers allow you to specify precise conditions for when a workflow should execute. The platform supports a comprehensive set of operators:

#### Comparison operators

| Operator | Description           | Example                          |
| :------- | :-------------------- | :------------------------------- |
| \~eq     | Equals                | `{"priority": {"~eq": "high"}}`  |
| \~neq    | Not equals            | `{"status": {"~neq": "closed"}}` |
| \~gt     | Greater than          | `{"value": {"~gt": 100}}`        |
| \~gte    | Greater than or equal | `{"age": {"~gte": 18}}`          |
| \~lt     | Less than             | `{"count": {"~lt": 5}}`          |
| \~lte    | Less than or equal    | `{"score": {"~lte": 10}}`        |

#### Collection operators

| Operator | Description  | Example                                    |
| :------- | :----------- | :----------------------------------------- |
| \~in     | In array     | `{"status": {"~in": ["open", "pending"]}}` |
| \~nin    | Not in array | `{"type": {"~nin": ["internal", "test"]}}` |

#### String operators

| Operator    | Description          | Example                                     |
| :---------- | :------------------- | :------------------------------------------ |
| \~regex     | Matches regex        | `{"email": {"~regex": ".*@company\\.com"}}` |
| \~nregex    | Does not match regex | `{"url": {"~nregex": ".*\\.test\\.com"}}`   |
| \~starts    | Starts with          | `{"name": {"~starts": "Test"}}`             |
| \~nstarts   | Does not start with  | `{"ref": {"~nstarts": "DRAFT"}}`            |
| \~ends      | Ends with            | `{"email": {"~ends": "@thena.ai"}}`         |
| \~nends     | Does not end with    | `{"path": {"~nends": ".tmp"}}`              |
| \~contains  | Contains             | `{"description": {"~contains": "urgent"}}`  |
| \~ncontains | Does not contain     | `{"title": {"~ncontains": "test"}}`         |

#### Special operators

| Operator  | Description | Example                           |
| :-------- | :---------- | :-------------------------------- |
| \~isnull  | Is null     | `{"assignee": {"~isnull": true}}` |
| \~isempty | Is empty    | `{"tags": {"~isempty": true}}`    |

#### Logical operators

| Operator | Description               | Example                                                                  |
| :------- | :------------------------ | :----------------------------------------------------------------------- |
| \~and    | All conditions must match | `{"~and": [{"status": {"~eq": "open"}}, {"priority": {"~eq": "high"}}]}` |
| \~or     | Any condition must match  | `{"~or": [{"type": {"~eq": "bug"}}, {"priority": {"~eq": "high"}}]}`     |

<Note>
  Filter operators can be combined to create complex conditions. The platform evaluates them in a deterministic order, with logical operators (\~and, \~or) being evaluated last.
</Note>

## Example trigger

```json theme={null}
{
  "name": "Change status to Waiting on Customer when an agent replies",
  "triggerEvent": "ticket:comment:created",
  "filters": {
    "~and": [
      {
        "{{context.event.message.payload.comment.teamId}}": {
          "~eq": "T66CEQQJXZ"
        }
      },
      {
        "~and": [
          {
            "~and": [
              {
                "{{ context.event.message.payload.ticket.status.name }}": {
                  "~neq": "Waiting on customer"
                }
              },
              {
                "{{ context.event.message.payload.comment.customerContact }}": {
                  "~isEmpty": true
                }
              },
              {
                "{{ context.event.message.payload.comment.commentVisibility }}": {
                  "~eq": "public"
                }
              },
              {
                "{{ context.event.message.payload.comment.commentType }}": {
                  "~eq": "comment"
                }
              }
            ]
          }
        ]
      }
    ]
  }
}
```

<Note>
  This example demonstrates:

  * Using context variables with dot notation to access nested properties
  * Combining multiple logical operators
  * Checking for specific team, status, and comment properties
  * Using various comparison and special operators
</Note>

## Platform events reference

<Info>
  Events are real-time notifications that your application can listen to when specific actions occur in the Thena platform.
  Each event contains metadata about when and where it was triggered, along with relevant payload data.
</Info>

### Event structure

All events in the Thena platform follow a consistent base structure:

```json theme={null}
{
  "event_id": "evt_123abc456def",
  "event_type": "ticket:created",
  "timestamp": "2025-01-26T12:34:56Z",
  "org_id": "org_789xyz",
  "team_id": "team_123abc",
  "actor": {
    "id": "usr_456def",
    "type": "user"
  },
  "payload": {
    // Event-specific data
  }
}
```

### Available events

#### Organization events

* `org:created` - When a new organization is created
* `org:updated` - When organization details are updated
* `org:deleted` - When an organization is deleted
* `org:settings:updated` - When organization settings are modified

#### Team events

* `team:created` - When a new team is created
* `team:updated` - When team details are updated
* `team:deleted` - When a team is deleted
* `team:member:added` - When a member is added to a team
* `team:member:removed` - When a member is removed from a team

#### User events

* `user:created` - When a new user is created
* `user:updated` - When user details are updated
* `user:deleted` - When a user is deleted
* `user:status:changed` - When a user's status changes
* `user:role:changed` - When a user's role is modified
* `user:login` - When a user logs in
* `user:logout` - When a user logs out

#### Ticket events

* `ticket:created` - When a new ticket is created
* `ticket:updated` - When ticket details are updated
* `ticket:deleted` - When a ticket is deleted
* `ticket:status:changed` - When a ticket's status changes
* `ticket:assigned` - When a ticket is assigned
* `ticket:unassigned` - When a ticket is unassigned
* `ticket:priority:changed` - When a ticket's priority changes
* `ticket:comment:added` - When a comment is added to a ticket
* `ticket:comment:updated` - When a comment is updated
* `ticket:comment:deleted` - When a comment is deleted
* `ticket:reaction:added` - When a reaction is added to a ticket
* `ticket:reaction:removed` - When a reaction is removed from a ticket
* `ticket:comment:reaction:added` - When a reaction is added to a comment
* `ticket:comment:reaction:removed` - When a reaction is removed from a comment

#### Account events

* `account:created` - When a new account is created
* `account:updated` - When account details are updated
* `account:deleted` - When an account is deleted
* `account:status:changed` - When an account's status changes

#### Customer events

* `customer:created` - When a new customer is created
* `customer:updated` - When customer details are updated
* `customer:deleted` - When a customer is deleted
* `customer:merged` - When customer records are merged

#### Custom field events

* `custom_field:created` - When a new custom field is created
* `custom_field:updated` - When a custom field is updated
* `custom_field:deleted` - When a custom field is deleted
* `custom_field:value:changed` - When a custom field value changes

#### Form events

* `form:created` - When a new form is created
* `form:updated` - When a form is updated
* `form:deleted` - When a form is deleted
* `form:submission:created` - When a form submission is received
* `form:submission:updated` - When a form submission is updated

#### SLA events

* `sla:created` - When a new SLA policy is created
* `sla:updated` - When an SLA policy is updated
* `sla:deleted` - When an SLA policy is deleted
* `sla:breach:warning` - When an SLA is about to breach
* `sla:breach:occurred` - When an SLA breach occurs

#### Workflow events

* `workflow:created` - When a new workflow is created
* `workflow:updated` - When a workflow is updated
* `workflow:deleted` - When a workflow is deleted
* `workflow:executed` - When a workflow starts execution
* `workflow:step:completed` - When a workflow step is completed
* `workflow:completed` - When a workflow execution completes

#### CSAT events

* `csat:survey:sent` - When a CSAT survey is sent
* `csat:response:received` - When a CSAT response is received
* `csat:feedback:updated` - When CSAT feedback is updated

#### App events

* `app:installed` - When an app is installed in a workspace
* `app:uninstalled` - When an app is uninstalled from a workspace
* `app:reinstalled` - When an app is reinstalled in a workspace
* `app:mentioned` - When an app is mentioned in a conversation
* `app:settings:updated` - When app settings are modified

#### Source integration events

##### Slack events

* `source:slack:message:received` - When a message is received from Slack
* `source:slack:thread:created` - When a new thread is created in Slack
* `source:slack:reaction:added` - When a reaction is added in Slack

##### MS Teams events

* `source:msteams:message:received` - When a message is received from MS Teams
* `source:msteams:thread:created` - When a new thread is created in MS Teams
* `source:msteams:reaction:added` - When a reaction is added in MS Teams

##### Email events

* `source:email:received` - When an email is received
* `source:email:bounced` - When an email bounces
* `source:email:replied` - When an email is replied to

##### Widget events

* `source:widget:opened` - When the widget is opened
* `source:widget:message:sent` - When a message is sent via widget
* `source:widget:closed` - When the widget is closed

### Event delivery and retries

Events are delivered in real-time with automatic retries on failure:

1. **First attempt**: Immediate delivery
2. **Second attempt**: After 3 minutes
3. **Final attempt**: After 5 minutes

<Warning>
  Your webhook endpoint must respond within 3 seconds, or the request will time out and trigger the retry mechanism.
</Warning>

<Warning>
  Design your event handlers to be idempotent as you may receive the same event multiple times during retries.
</Warning>

### Best practices for event consumers

#### Handling events reliably

* **Implement idempotency checks**: Store processed event IDs to avoid duplicate processing during retries
* **Use event timestamps**: Process events in chronological order using the `timestamp` field
* **Validate event data**: Always validate the event payload before processing to handle schema changes gracefully

#### Performance optimization

* **Process asynchronously**: Handle events in background workers to avoid blocking your main application
* **Batch related operations**: Group related database updates or API calls for better performance
* **Set reasonable timeouts**: Acknowledge webhooks within 3 seconds and process heavy tasks asynchronously
* **Queue long-running tasks**: If processing takes longer than 3 seconds, acknowledge the webhook and process in background

#### Error handling

* **Log processing errors**: Include event ID and type in error logs for easier debugging
* **Implement dead letter queues**: Store failed events separately for manual review
* **Monitor processing delays**: Set up alerts for event processing backlogs

#### Security

* **Validate webhook signatures**: Use the provided signature to verify event authenticity
* **Secure API keys**: Store webhook secret keys in secure environment variables
* **Filter by event types**: Subscribe only to events your application needs

#### Testing

* **Use the event simulator**: Test your handlers with simulated events before going live
* **Verify retry handling**: Test your idempotency logic with duplicate events
* **Monitor event processing**: Track success rates and processing times in production

<Note>
  Remember to version your event handlers to handle potential schema changes in future platform updates.
</Note>

### Example event payloads

<AccordionGroup>
  <Accordion title="App installation event (app:installed)">
    ```json theme={null}
    {
      "event_id": "evt_abc123def456",
      "event_type": "app:installed",
      "timestamp": "2025-01-23T14:19:50.300Z",
      "org_id": "EMMBB11RCN",
      "team_id": "TNN77BB6JF",
      "payload": {
        "app_id": "ZWS0M7JJ10JR39FSFR7HER0189DW3",
        "installed_by": "UKK7Z00C9Q",
        "installation_id": "ZWS0M7JJ10JR39FSFR7HER0189DW3",
        "bot_token": "UWW7M66C2Y",
        "settings": {
          "optional_settings": {},
          "required_settings": {
            "agent_studio_api_key": "Harsh"
          }
        }
      },
      "x_webhook_event": "app.installation"
    }
    ```
  </Accordion>

  <Accordion title="Ticket creation event (ticket:created)">
    ```json theme={null}
    {
      "event_id": "evt_abc123def456",
      "event_type": "ticket:created",
      "timestamp": "2025-01-26T12:34:56Z",
      "org_id": "org_789xyz",
      "team_id": "team_123abc",
      "actor": {
        "id": "usr_456def",
        "type": "user",
        "email": "john@example.com"
      },
      "payload": {
        "ticket": {
          "id": "tkt_789xyz",
          "title": "Need help with integration",
          "description": "Having issues connecting with Slack",
          "priority": "high",
          "status": "open",
          "source": "email",
          "created_at": "2025-01-26T12:34:56Z",
          "team_id": "team_123abc",
          "customer": {
            "id": "cust_123abc",
            "email": "customer@example.com",
            "name": "Jane Smith"
          },
          "assigned_to": null,
          "tags": ["integration", "slack"],
          "custom_fields": {
            "department": "IT",
            "category": "Integration"
          }
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="CSAT response event (csat:response:received)">
    ```json theme={null}
    {
      "event_id": "evt_uvw012xyz345",
      "event_type": "csat:response:received",
      "timestamp": "2025-01-26T15:00:00Z",
      "org_id": "org_789xyz",
      "team_id": "team_123abc",
      "actor": {
        "id": "cust_123abc",
        "type": "customer",
        "email": "customer@example.com"
      },
      "payload": {
        "survey": {
          "id": "srv_456def",
          "type": "ticket_resolution",
          "sent_at": "2025-01-26T14:30:00Z"
        },
        "ticket": {
          "id": "tkt_789xyz",
          "title": "Need help with integration",
          "resolved_by": {
            "id": "usr_456def",
            "name": "John Doe"
          }
        },
        "response": {
          "rating": 5,
          "comment": "Great service, very helpful!",
          "categories": ["knowledgeable", "quick_response"],
          "submitted_at": "2025-01-26T15:00:00Z"
        },
        "metrics": {
          "time_to_response": 1800,
          "resolution_time": 3600
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="MS Teams message event (source:msteams:message:received)">
    ```json theme={null}
    {
      "event_id": "evt_def345ghi678",
      "event_type": "source:msteams:message:received",
      "timestamp": "2025-01-26T15:30:00Z",
      "org_id": "org_789xyz",
      "team_id": "team_123abc",
      "actor": {
        "id": "msteams_usr_789",
        "type": "integration",
        "platform": "msteams"
      },
      "payload": {
        "message": {
          "id": "msteams_msg_123",
          "channel_id": "19:123456789@thread.tacv2",
          "team_name": "Customer Success",
          "user_id": "29:1abc2def3ghi",
          "user_name": "Bob Wilson",
          "text": "Need urgent assistance with API integration",
          "timestamp": "2025-01-26T15:30:00Z",
          "conversation_id": "19:123456789@thread.tacv2"
        },
        "converted_ticket": {
          "id": "tkt_901xyz",
          "source": "msteams",
          "source_thread_id": "19:123456789@thread.tacv2",
          "priority": "high"
        },
        "routing": {
          "assigned_team": "team_123abc",
          "routing_rule": "api_integration_issues"
        }
      }
    }
    ```
  </Accordion>
</AccordionGroup>
