---
updatedAt: 2026-04-06T16:22:26.000Z
agentTools:
  projectIndex: https://developers.newo.ai/llms.txt
---

# Events and the event system

Events are the primary mechanism through which the Newo platform triggers skill execution. Every user message, phone call, timer tick, API response, and inter-agent signal is represented as an event that flows through a subscription-based routing system to invoke the correct skill at the correct time.

## What is an event?

An event is a structured notification that something has happened. When a user sends a chat message, the platform emits a `user_message` event. When a voice call connects, it emits `conversation_started`. When a timer fires, it emits `timer`. Each event carries an identifier, a set of arguments, and metadata that tell the platform what happened and provide context for the skill that will process it.

Events are the glue between the outside world and agent intelligence. Without events, skills would have no trigger -- they would never execute. The event system ensures that the right skill runs in response to the right stimulus, on the right integration, at the right time.

## Event structure

Every event on the platform carries the following fields:

| **Field**           | **Type**         | **Description**                                                                                                                                                        |
| :------------------ | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `idn`               | `str`            | The event identifier (e.g., `user_message`, `conversation_started`, `timer`). This is the primary key used for routing.                                                |
| `arguments`         | `dict[str, str]` | Key-value payload carried with the event. For a `user_message`, this includes `text`. For a `conversation_ended`, it includes `callSid`, `reason`, and `recordingUrl`. |
| `uninterruptible`   | `bool`           | When `True`, the skill triggered by this event must complete without being interrupted by subsequent events. Defaults to `False`.                                      |
| `external_event_id` | `UUID` or `None` | An external identifier assigned by the connector or caller. Used for deduplication and tracing.                                                                        |
| `command_act_id`    | `UUID` or `None` | Links this event to a previously issued command, enabling request-response correlation (e.g., a `result_success` event referencing the command that initiated it).     |

The platform defines several standard event patterns:

| **Factory method**        | **Produces event `idn`** | **Purpose**                                                                                                           |
| :------------------------ | :----------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| `as_result_success()`     | `result_success`         | Signals that a command completed successfully. Carries a `referenceIdn` argument pointing to the originating command. |
| `as_result_error()`       | `result_error`           | Signals that a command failed. Carries `referenceIdn`, `errorType` (`user_error` or `server_error`), and a `message`. |
| `as_tool_called()`        | `tool_called`            | Emitted during voice-to-voice (V2V) sessions when the LLM invokes a tool. Carries `name` and `parameters`.            |
| `as_conversation_ended()` | `conversation_ended`     | Emitted when a voice call ends. Carries `callSid`, `reason`, and `recordingUrl`.                                      |

## Event subscription model

Events do not automatically invoke skills. A flow must explicitly subscribe to the events it wants to handle. Subscriptions are defined in the `events` section of a flow YAML file. Each subscription has the following fields:

| **Field**         | **Description**                                                                                                                                                                                                                                                           |
| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `idn`             | The event identifier to subscribe to (must match the `idn` of the incoming event).                                                                                                                                                                                        |
| `skill_selector`  | How the target skill is determined. `skill_idn` means the skill is hardcoded in the subscription. `skill_idn_from_state` means the skill identifier is read from a flow state field at runtime.                                                                           |
| `skill_idn`       | The identifier of the skill to execute. Used when `skill_selector` is `skill_idn`.                                                                                                                                                                                        |
| `state_idn`       | The identifier of the state field that holds the target skill name. Used when `skill_selector` is `skill_idn_from_state`.                                                                                                                                                 |
| `integration_idn` | Filters the subscription to events from a specific integration (e.g., `newo_voice`, `telegram`). When `null`, the subscription matches events from any integration.                                                                                                       |
| `connector_idn`   | Further narrows the filter to a specific connector within the integration. When `null`, any connector on the matched integration qualifies.                                                                                                                               |
| `interrupt_mode`  | Controls what happens when this event fires while the flow is already executing a skill. `interrupt` stops the current skill and starts the new one. `queue` waits for the current skill to finish, then runs. `cancel` discards the event if a skill is already running. |

### How event-to-skill routing works

When an event arrives, the platform evaluates every event subscription across all flows belonging to the target agent. A subscription matches when all of the following conditions are true:

1. The subscription's `idn` equals the event's `idn`.
2. If the subscription specifies an `integration_idn`, it must match the event's source integration.
3. If the subscription specifies a `connector_idn`, it must match the event's source connector.

When a match is found, the platform resolves the target skill:

* If `skill_selector` is `skill_idn`, the platform invokes the skill identified by `skill_idn`.
* If `skill_selector` is `skill_idn_from_state`, the platform reads the current value of the state field identified by `state_idn` and uses that value as the skill identifier.

The `interrupt_mode` then determines execution timing relative to any already-running skill.

:::
**🗒️ NOTE**
A single event can match multiple subscriptions across different flows within the same agent. Each matching subscription triggers its respective skill independently. This is how a `conversation_started` event can simultaneously initialize both the main conversation flow and the follow-up timer flow.
:::

## YAML event subscription configuration

Event subscriptions are declared in the `events` section of a flow YAML file. Below are annotated examples drawn from real Newo Agent Framework (NAF) flows.

### Basic subscription: conversation started on Newo Chat

```yaml
events:
  - idn: conversation_started
    skill_selector: skill_idn
    skill_idn: ConversationStartedSkill
    state_idn: null
    integration_idn: newo_chat
    connector_idn: null
    interrupt_mode: queue
```

This subscription listens for `conversation_started` events originating from the `newo_chat` integration, regardless of which connector. When triggered, it executes `ConversationStartedSkill` in queue mode.

### Same event, different integrations

The same event identifier can be subscribed to multiple times with different integration filters. This is how a single flow handles the same logical event across different channels:

```yaml
events:
  # Chat messages
  - idn: user_message
    skill_selector: skill_idn
    skill_idn: UserNewoChatReplySkill
    state_idn: null
    integration_idn: newo_chat
    connector_idn: newo_chat
    interrupt_mode: queue

  # SMS messages
  - idn: user_message
    skill_selector: skill_idn
    skill_idn: UserSMSReplySkill
    state_idn: null
    integration_idn: twilio_messenger
    connector_idn: sms_connector
    interrupt_mode: interrupt

  # Telegram messages
  - idn: user_message
    skill_selector: skill_idn
    skill_idn: UserTelegramReplySkill
    state_idn: null
    integration_idn: telegram
    connector_idn: telegram_connector
    interrupt_mode: interrupt

  # Voice messages (Newo Voice)
  - idn: user_message
    skill_selector: skill_idn_from_state
    skill_idn: null
    state_idn: phone_reply_skill
    integration_idn: newo_voice
    connector_idn: newo_voice_connector
    interrupt_mode: interrupt
```

Notice that the Newo Voice subscription uses `skill_idn_from_state`. The skill to execute is determined at runtime by reading the `phone_reply_skill` state field. This allows the agent to dynamically switch which skill handles voice messages based on the current conversation state.

### Timer subscription

```yaml
events:
  - idn: timer
    skill_selector: skill_idn
    skill_idn: FetchData
    state_idn: null
    integration_idn: program_timer
    connector_idn: data_injection_timer
    interrupt_mode: queue
```

Timer events come from the `program_timer` integration. The `connector_idn` identifies which specific timer fired, allowing a flow to subscribe to multiple timers with different handlers.

### Integration response subscription

```yaml
events:
  - idn: magic_browser_response
    skill_selector: skill_idn
    skill_idn: MWreceiveResponseSkill
    state_idn: null
    integration_idn: magic_browser
    connector_idn: magic_browser_connector
    interrupt_mode: queue
```

When a Magic Browser command finishes processing a web page, the platform emits a `magic_browser_response` event. This subscription routes that response to the appropriate processing skill.

### Custom event subscription

```yaml
events:
  - idn: end_session
    skill_selector: skill_idn
    skill_idn: EndSessionSkill
    state_idn: null
    integration_idn: system
    connector_idn: system
    interrupt_mode: queue
```

Custom events use `integration_idn: system` and `connector_idn: system`. The event identifier `end_session` is a custom event name defined by the application rather than a platform-standard event.

## Event identifier reference

The table below lists all core event identifiers recognized by the Newo platform.

### Conversation and session events

| **Event `idn`**        | **Source integration(s)**                     | **Description**                                                                                                                             | **Key arguments**                                                    |
| :--------------------- | :-------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------- |
| `conversation_started` | `newo_chat`, `newo_voice`, `vapi`, `telegram` | Fired when a new conversation begins -- a chat widget opens for the first time, a voice call is answered, or a Telegram user starts a chat. | `callSid`, `isSharedPhoneNumber` (voice only)                        |
| `conversation_ended`   | `newo_voice`, `vapi`                          | Fired when a voice call terminates.                                                                                                         | `callSid`, `reason`, `recordingUrl`, `callId`                        |
| `session_started`      | (any)                                         | Fired when a new logical session begins within the platform.                                                                                | --                                                                   |
| `session_ended`        | `system`                                      | Fired (typically via `SendSystemEvent`) when a session ends. Carries analytics data.                                                        | `transcript`, `summary`, `category`, `workingHours`, and many others |

### Message events

| **Event `idn`** | **Source integration(s)**                                                           | **Description**                                                                                   | **Key arguments**                |
| :-------------- | :---------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------ | :------------------------------- |
| `user_message`  | `newo_chat`, `newo_voice`, `vapi`, `telegram`, `twilio_messenger`, `sandbox`, `api` | Fired every time a user sends a message (text or transcribed voice).                              | `text`, `eosReason` (voice only) |
| `agent_message` | (any)                                                                               | Fired every time the agent sends a message. Used for tracking or post-processing agent responses. | --                               |

### Call and voice events

| **Event `idn`**                       | **Source integration(s)** | **Description**                                                               | **Key arguments**                          |
| :------------------------------------ | :------------------------ | :---------------------------------------------------------------------------- | :----------------------------------------- |
| `call_aborted`                        | `newo_voice`, `vapi`      | Fired when a user or agent hangs up the phone.                                | --                                         |
| `call_ended`                          | `newo_voice`, `vapi`      | Fired when a phone call cannot be started or finishes unexpectedly.           | --                                         |
| `user_speech_started`                 | `newo_voice`              | Fired when the platform detects the user has begun speaking.                  | --                                         |
| `user_speech_detected`                | `newo_voice`              | Fired during speech recognition with interim and final transcription results. | `text`, `isEnded`, `speaker`, `confidence` |
| `agent_speech_ended`                  | `newo_voice`              | Fired when the agent finishes speaking a response.                            | --                                         |
| `agent_speech_started`                | `newo_voice`              | Fired when the agent begins speaking.                                         | --                                         |
| `user_message_transcription_finished` | `newo_voice`              | Fired when the final transcription of a user's spoken turn is complete.       | --                                         |
| `tool_called`                         | `newo_voice`              | Fired during V2V sessions when the LLM invokes a function/tool.               | `name`, `parameters`, `callId`             |

### Response events

| **Event `idn`**          | **Source integration(s)** | **Description**                                                                  | **Key arguments**         |
| :----------------------- | :------------------------ | :------------------------------------------------------------------------------- | :------------------------ |
| `magic_http_response`    | `http`                    | Fired when the HTTP connector receives a response from a `send_request` command. | Response body and headers |
| `magic_api_response`     | `magic_api`               | Fired when the Magic API connector receives a response from the target API.      | Response data             |
| `magic_browser_response` | `magic_browser`           | Fired when the Magic Browser connector finishes processing a web page or action. | Response data             |

### Command result events

| **Event `idn`**  | **Source integration(s)**  | **Description**                                                | **Key arguments**                           |
| :--------------- | :------------------------- | :------------------------------------------------------------- | :------------------------------------------ |
| `result_success` | (varies by command target) | Fired when a previously issued command completes successfully. | `referenceIdn` (the command that succeeded) |
| `result_error`   | (varies by command target) | Fired when a previously issued command fails.                  | `referenceIdn`, `errorType`, `message`      |

### Timer events

| **Event `idn`**         | **Source integration(s)** | **Description**                                                                                 | **Key arguments** |
| :---------------------- | :------------------------ | :---------------------------------------------------------------------------------------------- | :---------------- |
| `timer`                 | `program_timer`           | Fired when a programmable timer fires. The specific timer is identified by the `connector_idn`. | --                |
| `follow_up_message`     | `program_timer`           | Fired by the follow-up timer to prompt the agent to send a follow-up message.                   | --                |
| `waiting_mode_fallback` | `program_timer`           | Fired as a fallback when the agent has been in waiting mode for too long.                       | --                |

### System and custom events

| **Event `idn`**          | **Source integration(s)** | **Description**                                                                                       | **Key arguments** |
| :----------------------- | :------------------------ | :---------------------------------------------------------------------------------------------------- | :---------------- |
| `project_init`           | (any)                     | Fired when a project is initialized for the first time.                                               | --                |
| `project_publish_finish` | `system`                  | Fired when project publishing completes.                                                              | --                |
| `interrupt`              | `newo_voice`              | Fired when the user interrupts the agent during speech.                                               | `streamId`        |
| `interrupt_mode_changed` | `newo_voice`              | Fired when the interrupt mode setting changes.                                                        | `interruptMode`   |
| *(custom)*               | `system`                  | Any custom event emitted via `SendSystemEvent`. The `idn` is whatever string the developer specifies. | Developer-defined |

:::
**🗒️ NOTE**
This list covers the core platform events. Custom events with arbitrary identifiers can be created using the `SendSystemEvent` action. See the section below for details.
:::

## Connector event payloads

When events arrive from external connectors (such as webhooks), they carry additional routing metadata:

| **Field**           | **Description**                                                          |
| :------------------ | :----------------------------------------------------------------------- |
| `integration_idn`   | The integration this event originates from (e.g., `api`, `telegram`).    |
| `connector_idn`     | The specific connector instance (e.g., `webhook`, `telegram_connector`). |
| `event_idn`         | The event identifier (e.g., `user_message`).                             |
| `command_act_id`    | Links to a command if this event is a response to one.                   |
| `user_actor_id`     | The actor ID of the user associated with this event.                     |
| `external_event_id` | A caller-supplied UUID for tracing and deduplication.                    |
| `arguments`         | A list of name-value pairs carrying the event payload.                   |
| `uninterruptible`   | Whether the triggered skill should be protected from interruption.       |

Each argument in the `arguments` list is a name-value pair: `name` (string) and `value` (string).

## Event emission pipeline

Understanding how events travel from their source to a skill helps clarify the system architecture. The sequence is:

1. **Source emits event** -- A service (voice, webhooks, chat, timer, or another agent) creates an event and passes it to the event emitter.
2. **Event emitter serializes and dispatches** -- The event emitter serializes the arguments and sends them to the Flow Runner.
3. **Flow Runner matches subscriptions** -- The Flow Runner evaluates the incoming event against all subscriptions for the target agent. It checks `idn`, `integration_idn`, and `connector_idn`.
4. **Skill resolution** -- For each matching subscription, the Flow Runner resolves the target skill (from `skill_idn` or from a state field).
5. **Interrupt mode evaluation** -- The Flow Runner applies the `interrupt_mode` rule to determine whether to start immediately, queue, or cancel.
6. **Skill execution** -- The resolved skill runs with access to the event's arguments via the `GetTriggeredAct()` action.

```mermaid
flowchart TD
    Source["Source<br/>voice · chat · webhook · timer · agent"] --> Event["Event<br/>idn + arguments"]
    Event --> Emitter["Event Emitter<br/>serializes arguments"]
    Emitter --> Runner["Flow Runner<br/>matches subscriptions"]
    Runner --> M1["Match subscription 1"] --> SA["Skill A<br/>interrupt mode"]
    Runner --> M2["Match subscription 2"] --> SB["Skill B<br/>queue mode"]
    Runner --> NoM["No match"] --> Ignored["event ignored"]
```

## Custom events with `SendSystemEvent`

The `SendSystemEvent` action allows skills to emit arbitrary custom events. This is the primary mechanism for inter-agent communication, multi-step workflows, and application-defined signaling.

```
SendSystemEvent(
  eventIdn: str,
  connectorIdn: str = "system",
  actorIds: List[str] | None = None,
  global: Literal['true', 'false'] = 'false',
  uninterruptible: Literal['true', 'false'] | None = None,
  **arguments: str
)
```

| **Parameter**     | **Description**                                                                                 |
| :---------------- | :---------------------------------------------------------------------------------------------- |
| `eventIdn`        | The custom event identifier. Can be any string.                                                 |
| `connectorIdn`    | The connector identifier for the event. Defaults to `"system"`.                                 |
| `actorIds`        | List of actor IDs to send this event to. If omitted, the event targets the current actor.       |
| `global`          | If `"true"`, the event is broadcast globally. The `actorIds` parameter is ignored in this case. |
| `uninterruptible` | If `"true"`, the skill triggered by this event cannot be interrupted by subsequent events.      |
| `**arguments`     | Any additional keyword arguments are sent as event arguments (name-value pairs).                |

### Sending a custom event

The following skill script emits a custom event called `my_custom_event` with four arguments:

```
{{SendSystemEvent(
    eventIdn="my_custom_event",
    last_user_message_text=GetTriggeredAct(fields=['text']),
    last_agent_message_text=RESULT,
    my_argument_1="MY ARGUMENT VALUE 1",
    my_argument_2="MY ARGUMENT VALUE 2"
)}}
```

### Subscribing to a custom event

To handle the custom event, another flow subscribes with `integration_idn: system` and `connector_idn: system`:

```yaml
events:
  - idn: my_custom_event
    skill_selector: skill_idn
    skill_idn: HandleCustomEventSkill
    state_idn: null
    integration_idn: system
    connector_idn: system
    interrupt_mode: queue
```

### Reading event arguments in the receiving skill

The receiving skill retrieves the event's arguments using `GetTriggeredAct`:

```
{{set(name='act_info', value=GetTriggeredAct(fields=[
    'my_argument_1',
    'my_argument_2',
    'last_user_message_text',
    'last_agent_message_text'
]))}}
```

### Real-world example: session ended event

The NAF uses `SendSystemEvent` extensively for inter-agent signaling. When a conversation session ends, the `CAEndSessionFlow` emits a `session_ended` event packed with analytics data:

```
{{SendSystemEvent(
    eventIdn="session_ended",
    connectorIdn="system",
    businessEmail=business_email,
    businessLabel=business_name,
    transcript=transcript,
    summary=summary,
    recordingUrls=recording_urls,
    workingHours=working_hours_status,
    category=category,
    success=success_classification,
    potentialRevenue=potential_revenue
)}}
```

Other agents and external systems can subscribe to this event to perform post-conversation processing -- updating CRM records, sending reports, triggering webhooks, and more.

:::
**❗❗ IMPORTANT**
Custom events sent with `SendSystemEvent` use `integration_idn: system` and `connector_idn: system` by default. The receiving flow's event subscription must match these values, or the event will not be routed.
:::

## Integration-specific event mapping

Different integrations emit different subsets of events. The table below maps each integration to the events it can produce.

| **Integration `idn`** | **Events emitted**                                                                                                                                                                                                                                                                       |
| :-------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `newo_chat`           | `conversation_started`, `user_message`                                                                                                                                                                                                                                                   |
| `newo_voice`          | `conversation_started`, `conversation_ended`, `user_message`, `user_speech_started`, `user_speech_detected`, `agent_speech_ended`, `agent_speech_started`, `user_message_transcription_finished`, `tool_called`, `interrupt`, `interrupt_mode_changed`, `result_success`, `result_error` |
| `vapi`                | `conversation_started`, `conversation_ended`, `user_message`, `call_aborted`, `call_ended`                                                                                                                                                                                               |
| `telegram`            | `conversation_started`, `user_message`                                                                                                                                                                                                                                                   |
| `twilio_messenger`    | `user_message`, `result_success`                                                                                                                                                                                                                                                         |
| `sandbox`             | `user_message`                                                                                                                                                                                                                                                                           |
| `api`                 | `user_message`                                                                                                                                                                                                                                                                           |
| `http`                | `magic_http_response`                                                                                                                                                                                                                                                                    |
| `magic_api`           | `magic_api_response`                                                                                                                                                                                                                                                                     |
| `magic_browser`       | `magic_browser_response`                                                                                                                                                                                                                                                                 |
| `program_timer`       | `timer`, `follow_up_message`, `waiting_mode_fallback`                                                                                                                                                                                                                                    |
| `system`              | Any custom event via `SendSystemEvent`                                                                                                                                                                                                                                                   |

:::
**🗒️ NOTE**
The `result_success` and `result_error` events can originate from any integration that supports commands. The integration listed in the event's source metadata corresponds to the integration where the original command was sent.
:::

## Interrupt modes explained

The `interrupt_mode` field on an event subscription controls concurrency behavior within a flow. Choosing the right mode is critical for correct agent behavior.

| **Mode**    | **Behavior**                                                                  | **Use when**                                                                                                                                      |
| :---------- | :---------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |
| `interrupt` | Immediately stops the currently running skill and starts the new one.         | The new event should take priority. Common for voice `user_message` events where the user's latest input supersedes whatever the agent was doing. |
| `queue`     | Waits for the currently running skill to finish, then executes the new skill. | Both the current and new work are important. Common for `conversation_ended` and custom system events.                                            |
| `cancel`    | Discards the event entirely if a skill is already running.                    | The event is only relevant when the flow is idle. Used for low-priority background signals.                                                       |

In practice, the NAF uses `interrupt` for real-time user input on voice channels (where responsiveness is critical) and `queue` for most other events (where data integrity matters more than immediacy).

```mermaid
flowchart TD
    Arrives["New event arrives"] --> Check{"Is a skill<br/>already running?"}
    Check -->|No| Start["Start skill immediately"]
    Check -->|Yes| Mode{"interrupt_mode?"}
    Mode -->|interrupt| StopStart["Stop current skill<br/>Start new skill now"]
    Mode -->|queue| WaitRun["Wait for current skill<br/>to finish, then start"]
    Mode -->|cancel| Drop["Discard event"]
```

## Further reading

* See **Integrations and connectors** for details on integration types, connector configuration, and how events relate to the `outgoing_events_descriptions` field.
* See **Agents and the multi-agent system** for how events enable inter-agent communication within the NAF.
* See **SendSystemEvent** in the Actions reference for the full action specification and additional examples.
* See **Event Identifier List** for a quick-reference list of all event identifiers.