
Activator Authoring Cli
- 88 installs
- 934 repo stars
- Updated July 30, 2026
- microsoft/skills-for-fabric
activator-authoring-cli is an agent skill for creating and managing Microsoft Fabric Activator reflex alerts and notification rules via REST API and az rest CLI.
About
The activator-authoring-cli skill is a Microsoft Fabric workflow for building and managing Activator reflex items and alert rules entirely through the Fabric REST API and az rest CLI. It covers workspace and item ID resolution, reflex CRUD on the reflexes endpoint, and rule management via getDefinition and updateDefinition against Base64-encoded ReflexEntities.json payloads. Supported data sources include Eventstream sinks, KQL Eventhouse queries, Digital Twin Builder ontology connections, and Real-time Hub subscriptions, each with dedicated reference schemas for entity assembly. Rule conditions support detection thresholds, aggregation windows, occurrence options, and enrichments, while action types include TeamsMessage, EmailMessage, and FabricItemInvocation. The skill mandates Python json.dumps for building nested JSON strings because PowerShell ConvertTo-Json corrupts payloads, and it requires fabric_lro polling for long-running operations. Triggers include create an alert, notify me when, send a teams message when, or update an activator rule. Use whenever operators need CLI-authored Fabric Activator alerts tied to real-time analytics sources.
- Full reflex CRUD and rule editing via Fabric REST API and az rest.
- Supports Eventstream, KQL, DTB ontology, and Real-time Hub source types.
- Mandates Python for ReflexEntities.json assembly to avoid PowerShell corruption.
- Documents rule conditions, enrichments, and Teams, email, and item actions.
- Includes LRO polling patterns and workspace or item ID resolution guidance.
Activator Authoring Cli by the numbers
- 88 all-time installs (skills.sh)
- +7 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #852 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
activator-authoring-cli capabilities & compatibility
- Capabilities
- reflex item crud via fabric rest api · reflexentities rule assembly and update · multi source alert wiring for kql and eventstrea · teams, email, and fabric item action configurati · lro polling and python payload encoding
- Works with
- azure · teams
- Use cases
- orchestration · planning
npx skills add https://github.com/microsoft/skills-for-fabric --skill activator-authoring-cliAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 88 |
|---|---|
| repo stars | ★ 934 |
| Last updated | July 30, 2026 |
| Repository | microsoft/skills-for-fabric ↗ |
How do I create or update Fabric Activator alerts that notify Teams or email when analytics data crosses thresholds?
Create, update, or troubleshoot Microsoft Fabric Activator reflex rules that send Teams messages, emails, or pipeline actions when Eventhouse, Eventstream, KQL, DTB, or Real-time Hub data crosses thr.
Who is it for?
Fabric operators authoring CLI-driven Activator alerts on Eventhouse, Eventstream, KQL, DTB, or Real-time Hub data.
Skip if: Skip for non-Fabric alerting, GUI-only Activator setup without CLI automation, or unrelated pipeline authoring.
When should I use this skill?
User asks to create an alert, reflex rule, Teams notification, or update Fabric Activator thresholds.
What you get
A configured Activator reflex item with decoded ReflexEntities rules, sources, conditions, and notification actions.
Files
Update Check — ONCE PER SESSION (mandatory)
The first time this skill is used in a session, run the check-updates skill before proceeding.
- GitHub Copilot CLI / VS Code: invoke thecheck-updatesskill (e.g.,/fabric-skills:check-updates).
- Claude Code / Cowork / Cursor / Windsurf / Codex: read the localpackage.jsonversion, then compare it against the remote version viagit fetch origin main --quiet && git show origin/main:package.json(or the GitHub API). If the remote version is newer, show the changelog and update instructions.
- Skip if the check was already performed earlier in this session.
CRITICAL NOTES
1. To find the workspace details (including its ID) from workspace name: list all workspaces and, then, use JMESPath filtering
2. To find the item details (including its ID) from workspace ID, item type, and item name: list all items of that type in that workspace and, then, use JMESPath filtering
activator-authoring-cli — Activator Item & Rule Authoring via CLI
Table of Contents
| Task | Reference | Notes |
|---|---|---|
| Finding Workspaces and Items in Fabric | COMMON-CLI.md § Finding Workspaces and Items in Fabric | Mandatory — READ link first [needed for workspace/item ID resolution] |
| Authentication & Token Acquisition | COMMON-CORE.md § Authentication & Token Acquisition | Wrong audience = 401 |
| Authentication Recipes | COMMON-CLI.md § Authentication Recipes | Use the shared az login / token guidance from common docs |
| Core Control-Plane REST APIs | COMMON-CORE.md § Core Control-Plane REST APIs | List Workspaces, List Items, Item Creation |
| Long-Running Operations (LRO) | COMMON-CORE.md § Long-Running Operations (LRO) | Create, getDefinition, updateDefinition may return 202 |
| Fabric Item Definitions | ITEM-DEFINITIONS-CORE.md § Definition Envelope | Base64-encoded parts structure |
Fabric Control-Plane API via az rest | COMMON-CLI.md § Fabric Control-Plane API via az rest | Always pass `--resource https://api.fabric.microsoft.com` |
| LRO Pattern | COMMON-CLI.md § Long-Running Operations (LRO) Pattern | Poll 202 responses |
| Entity Types, Sources & Views | source-types.md | Entity envelope, source entities, and timeSeriesView-v1 variants |
| Eventstream Source | eventstream-source.md | Push-source workflow: create Eventstream sink first, then extend the discovered Activator entities |
| KQL Source | kql-source.md | KQL source schema, time-axis support, design guidance |
| Digital Twin Builder / Ontology Source | dtb-source.md | DTB / ontology source schema, JSON-string query payloads, snapshot vs time-axis guidance |
| Real-time Hub Source | real-time-hub-source.md | Real-time Hub source schema, workspace event types |
| Rule Conditions | rule-conditions.md | Rule template structure, detection conditions, aggregation, time windows, occurrence options, enrichments |
| Action Types | action-types.md | TeamsMessage, EmailMessage, FabricItemInvocation action schemas |
---
Tool Stack
| Tool | Purpose |
|---|---|
| az CLI | Fabric authentication and REST API token acquisition |
| curl | Header-aware Fabric REST calls through the shared fabric_lro helper |
| jq | JSON filtering and decoded definition inspection |
| python | MUST use for building ReflexEntities.json — json.dumps() handles nested stringification correctly. PowerShell's ConvertTo-Json corrupts nested JSON strings. |
⚠️ CRITICAL: Always use Python (not PowerShell) to build the ReflexEntities.json payload and the API request body.
Python Patterns
import json, base64, uuid
# Stringify template → JSON string for definition.instance
instance_string = json.dumps(template_dict, separators=(',', ':'))
# Encode entities and write updateDefinition request body
payload_b64 = base64.b64encode(json.dumps(entities).encode('utf-8')).decode('utf-8')
body = json.dumps({"definition": {"parts": [{"path": "ReflexEntities.json", "payload": payload_b64, "payloadType": "InlineBase64"}]}})
with open('update-body.json', 'w', encoding='utf-8') as f:
f.write(body)
# Then: az rest --method POST --url "...updateDefinition" --resource "https://api.fabric.microsoft.com" --body @update-body.json
# Decode a getDefinition response
response = json.loads(api_output)
for part in response['definition']['parts']:
if part['path'] == 'ReflexEntities.json':
entities = json.loads(base64.b64decode(part['payload']).decode('utf-8'))
# Generate GUIDs for uniqueIdentifier and step id fields
entity_id = str(uuid.uuid4())---
Connection
Use the shared authentication guidance in COMMON-CLI.md § Authentication Recipes. Resolve workspace and item IDs per COMMON-CLI.md § Finding Workspaces and Items in Fabric. Examples below assume WS_ID and REFLEX_ID are already resolved.
---
Item CRUD
Use the shared mechanics in COMMON-CLI.md § Item CRUD Operations. Activator uses the reflexes endpoint rather than the generic items endpoint:
| Operation | Endpoint | Method | Scopes | Notes |
|---|---|---|---|---|
| Create | /v1/workspaces/{workspaceId}/reflexes | POST | Reflex.ReadWrite.All or Item.ReadWrite.All | May return 202 LRO — use fabric_lro from COMMON-CLI |
| Update metadata | /v1/workspaces/{workspaceId}/reflexes/{reflexId} | PATCH | Reflex.ReadWrite.All or Item.ReadWrite.All | Follow COMMON-CLI metadata update pattern |
| Delete | /v1/workspaces/{workspaceId}/reflexes/{reflexId} | DELETE | Reflex.ReadWrite.All or Item.ReadWrite.All | Add ?hardDelete=true for permanent deletion |
getDefinition | /v1/workspaces/{workspaceId}/reflexes/{reflexId}/getDefinition | POST | Reflex.ReadWrite.All or Item.ReadWrite.All | Empty body required; may return 202 LRO — use fabric_lro |
updateDefinition | /v1/workspaces/{workspaceId}/reflexes/{reflexId}/updateDefinition | POST | Reflex.ReadWrite.All or Item.ReadWrite.All | Use Python to build update-body.json, then follow COMMON-CLI updateDefinition pattern |
---
Rule Management via Definitions
Rules are managed through getDefinition and updateDefinition. The payload is ReflexEntities.json, a Base64-encoded JSON array of entity objects. Workflow: Get → Decode → Modify → Re-encode → Update.
Get Definition
getDefinitionis a POST (not GET), requires ReadWrite scopes, and may return 202 LRO. Use thefabric_lrohelper from COMMON-CLI.md § Long-Running Operations (LRO) Pattern so 202 responses can be polled via theLocationheader before decoding.
DEFINITION=$(fabric_lro POST \
"https://api.fabric.microsoft.com/v1/workspaces/${WS_ID}/reflexes/${REFLEX_ID}/getDefinition" \
'{}')
echo "$DEFINITION" \
| jq '.definition.parts[] | select(.path=="ReflexEntities.json") | .payload' -r \
| base64 -d | jq .Update Definition
MUST use Python to buildupdate-body.json(see Python Patterns), then upload it using the COMMON-CLI updateDefinition pattern against/v1/workspaces/{workspaceId}/reflexes/{reflexId}/updateDefinition.
ReflexEntities.json — Assembly Procedure
Build a JSON array of entities in order. Each needs a fresh GUID for uniqueIdentifier. For the hand-authored pull-source flows in this skill, use templateVersion 1.2.4. For Eventstream sink-created flows, preserve the template version already present in the decoded Activator definition; those readbacks can use 1.1.
Step 1 — Container (exactly 1):
- Type:
container-v1. Use the container payload type that matches the source graph:kqlQueriesfor KQL sources,rthSubscriptionsfor Real-Time Hub workspace subscriptions, or the service-created type already present in readback for Eventstream flows. - All other entities reference this via
parentContainer.targetUniqueIdentifier
Step 2 — Data Source (exactly 1, pick the right type):
- See eventstream-source.md, kql-source.md, dtb-source.md, or real-time-hub-source.md for the supported source workflows
- For hand-authored pull sources, set
parentContainer.targetUniqueIdentifier→ Container GUID - For
eventstreamSource-v1: do not start by hand-authoring the source. Create or update the Eventstream with anActivatordestination first, then read the Activator definition and continue from the auto-createdeventstreamSource-v1+ SourceEvent entities. In public readback, those sink-created entities can appear without explicitparentContainer. - For
kqlSource-v1: the KQL query should return ALL data (do NOT pre-filter conditions — let the rule handle that). Must includeeventhouseItem,metadata, andqueryParameters. For Fabric Eventhouse/KQL DB sources, useeventhouseItem: { itemId, workspaceId, itemType: "KustoDatabase" }. For external ADX/Kusto sources, useeventhouseItem: { clusterHostName, databaseName }. Before creating the Activator, run the KQL directly against the target source first and confirm the returned columns, timestamp field, and row shape are correct. Use `eventTimeSettings` plus `DURATION_START`/`DURATION_END` queryParameters whenever the query results have a reasonable timestamp column, and declare those parameters in the KQL with `declare query_parameters(startTime:datetime, endTime:datetime);`. Only use snapshot mode (queryParameters: [], noeventTimeSettings, no time filtering) when the underlying data has no reasonable timestamp column and each row represents current state. See kql-source.md. - For
digitalTwinBuilderSource-v1: use a DTB / Ontologyconnectionitem ref{ itemId, workspaceId, itemType }, whereitemTypeis eitherDigitalTwinBuilderorOntology.query.queryStringmust be a JSON-string payload, not KQL. Before creating the Activator, run the DTB / Ontology query directly first and confirm the returned columns, key fields, and timestamp field are correct. PrefereventTimeSettingsplusDURATION_START/DURATION_ENDquery parameters when the returned rows include a reasonable timestamp field; unlike KQL, those duration parameters are applied as DTB endpoint URL query params rather than referenced inside the query body. See dtb-source.md.
Step 3 — SourceEvent view (exactly 1):
- Type:
timeSeriesView-v1, definition.type:"Event", instance:SourceEventtemplate referencing Source byentityId - For hand-authored pull-source flows, set
parentContainer→ Container GUID - For Eventstream sink-created flows, reuse the auto-created SourceEvent from readback instead of creating a second one
Step 4 — Choose the entity graph based on trigger type
- For `AttributeTrigger` rules (thresholds, ranges, text matches, boolean checks, aggregations):
- Create an Object view
- Optionally create SplitEvent if events must be mapped to object instances
- Create IdentityPartAttribute and any required BasicEventAttribute entities
- The rule then references those value attributes in
ScalarSelectStep
- For `EventTrigger` rules (fire on every event, heartbeat, event field state/change):
- Use the minimal graph: Container → Source → SourceEvent → Rule (+ optional
fabricItemAction-v1) - Do NOT create Object, SplitEvent, IdentityPartAttribute, or BasicEventAttribute entities unless the scenario truly needs attribute-based modeling
- EventTrigger reads raw event fields directly in
FieldsDefaultsStep/EventDetectStep
Step 5 — Rule (1 per alert):
- Type:
timeSeriesView-v1, definition.type:"Rule" - Always add `"description": "Created by: skills-for-fabric"` for user clarity
- Instance: rule template (see rule-conditions.md)
AttributeTrigger(v1.2.4): ScalarSelectStep → ScalarDetectStep → (DimensionalFilterStep)* → ActStepEventTrigger(v1.2.4): FieldsDefaultsStep → (EventDetectStep)+ → (DimensionalFilterStep)* → ActStepinstanceMUST be a JSON string (usejson.dumps())- Every template step inside
instance.steps[]needs anidGUID. Missing step IDs can produce invalid expression graphs because backend translators use the step ID as the output node ID. - For
AttributeTrigger, setparentObject→ Object andparentContainer→ Container - For
EventTrigger, setparentContainer→ Container and omitparentObjectunless the design explicitly requires it - Default to
settings: { "shouldRun": true, "shouldApplyRuleOnUpdate": false }so newly created rules start in the started / running state - Only set
shouldRun: falsewhen the user explicitly asks for a stopped rule or when a specific safe verification / eval workflow requires a disabled rule to avoid side effects - For
TeamsMessageactions with dynamic content, preserve the field-specific reference shapes from working readback: inline mixed-content fragments inheadline/optionalMessageuseAttributeReferencewithtype: "complex", while structuredadditionalInformationentries useNameReferencePair+AttributeReference/EventFieldReferencewithtype: "complexReference"andname: "reference"
Example rule entity:
{
"uniqueIdentifier": "<rule-guid>",
"payload": {
"name": "My Rule Name",
"description": "Created by: skills-for-fabric", # Required for user clarity
"parentObject": {"targetUniqueIdentifier": "<object-guid>"},
"parentContainer": {"targetUniqueIdentifier": "<container-guid>"},
"definition": {
"type": "Rule",
"instance": stringify_instance(rule_template),
"settings": {"shouldRun": True, "shouldApplyRuleOnUpdate": False}
}
},
"type": "timeSeriesView-v1"
}Step 6 — Fabric Item Action (only for FabricItemInvocation):
- Type:
fabricItemAction-v1— use this standalone action entity whenever the rule invokes a Fabric item such as a Pipeline, Notebook, Spark job definition, Dataflow, or UDF / Function Set - In the rule's
FabricItemBinding, setfabricJobConnectionDocumentIdto the standalonefabricItemAction-v1.uniqueIdentifier - See action-types.md for per-target schemas and UDF-specific gotchas (
itemTypevs readbackFunctionSet,subitemId, canonicalparameterTypemapping, dynamic parameter shape)
Entity Wiring Summary
Container ← everything references this via parentContainer
│
├── Source ← parentContainer → Container
│
├── SourceEvent ← parentContainer → Container
│ │ instance references Source by entityId
│ │
│ ├── EventTrigger Rule ← parentContainer → Container
│ │ minimal event-only path; reads raw event fields directly
│ │
│ └── Object ← parentContainer → Container
│ │
│ ├── (SplitEvent) ← OPTIONAL, parentObject → Object, parentContainer → Container
│ │ instance references SourceEvent by entityId
│ │ maps events to objects via FieldIdMapping
│ │
│ ├── Identity Attr ← parentObject → Object, parentContainer → Container
│ │
│ ├── Value Attr(s) ← parentObject → Object, parentContainer → Container
│ │ instance references SourceEvent (or SplitEvent if used) by entityId
│ │
│ └── AttributeTrigger Rule ← parentObject → Object, parentContainer → Container
│ instance references Value Attr by entityId in ScalarSelectStep
│
└── (FabricItemAction) ← parentContainer → Container (for any FabricItemInvocation action: Pipeline, Notebook, Spark job, Dataflow, or UDF / Function Set)Critical: definition.instance is a JSON String
instance inside timeSeriesView-v1 entity's definition is a JSON-encoded string, not a nested object. Always wrap rule templates in the full entity envelope.
❌ WRONG — raw template object (will fail):
{
"templateId": "AttributeTrigger",
"templateVersion": "1.2.4",
"steps": [...]
}✅ CORRECT — entity envelope with stringified instance:
{
"uniqueIdentifier": "<new-guid>",
"payload": {
"name": "My Rule Name",
"parentObject": { "targetUniqueIdentifier": "<object-guid>" },
"parentContainer": { "targetUniqueIdentifier": "<container-guid>" },
"definition": {
"type": "Rule",
"instance": "{\"templateId\":\"AttributeTrigger\",\"templateVersion\":\"1.2.4\",\"steps\":[...]}",
"settings": { "shouldRun": true, "shouldApplyRuleOnUpdate": false }
}
},
"type": "timeSeriesView-v1"
}Use json.dumps() to stringify. Do NOT use PowerShell's `ConvertTo-Json`.
Two Rule Template Types
| Template | When to Use | Steps |
|---|---|---|
AttributeTrigger | Monitor attribute value (numeric, text, boolean) | ScalarSelectStep → ScalarDetectStep → (DimensionalFilterStep)* → ActStep |
EventTrigger | Fire on event occurrence (state, change, heartbeat) | FieldsDefaultsStep → (EventDetectStep)+ → (DimensionalFilterStep)* → ActStep |
EventTrigger does NOT have ScalarSelectStep/ScalarDetectStep. Use when acting on events directly. Supports state, change, and heartbeat detection via EventDetectStep.
---
Must / Prefer / Avoid
MUST DO
- Always use `--resource https://api.fabric.microsoft.com` with
az rest— without it, token audience is wrong - Always send `--body '{}'` for
getDefinition— it is a POST and omitting the body can cause 411 errors - Always Base64-encode
ReflexEntities.jsonpayload when callingupdateDefinition - Always JSON.stringify the
definition.instancefield intimeSeriesView-v1entities — it must be a string, not a nested object. Always wrap rule templates in the full entity envelope (see the ❌/✅ example above) — never output a raw template object without the entity wrapper - Always use the correct template type —
AttributeTriggerfor value-based conditions (has ScalarSelectStep + ScalarDetectStep),EventTriggerfor event-based firing (has FieldsDefaultsStep + EventDetectStep, no ScalarDetectStep) - Always use new GUIDs for
uniqueIdentifierwhen adding entities — duplicate GUIDs cause corruption - Always update all cross-references when changing a
uniqueIdentifier— other entities reference it viatargetUniqueIdentifier - Handle LRO responses —
create,getDefinition, andupdateDefinitionmay return 202; poll theLocationheader
PREFER
- Read-modify-write over full replacement — get the current definition, modify the entity array, and update
- Soft delete over hard delete unless permanent removal is intended
- Discover IDs dynamically via workspace listing + JMESPath rather than hardcoding GUIDs
- Transition-based alert conditions over steady-state conditions for most alerts — prefer detectors such as
NumberBecomes,NumberEntersOrLeavesRange,LogicalBecomes, or explicit change conditions even when the user says casual state-like wording such as "is greater than", "is below", or "is outside the range". Treat ordinary alert wording as "notify me when it crosses into that state" to avoid repeated notifications while the condition remains true - Steady-state conditions such as
IsGreaterThan,IsLessThan, orIsOutsideRangeonly when the user explicitly asks for repeated firing while the value stays in the triggered state, for example "notify me every time it is greater than 30", "fire on every evaluation while it is above 30", or when a downstream occurrence / windowing pattern truly depends on that semantics
AVOID
- Hardcoded workspace or item IDs — always resolve dynamically
- Forgetting the `.platform` part — only include it with
updateDefinitionwhen using?updateMetadata=true - *SELECT without filtering** on list endpoints — use pagination for large workspaces
- Modifying definitions of items with encrypted sensitivity labels —
getDefinitionis blocked - Pre-filtering conditions in the KQL query — return all data from KQL and let the Activator rule steps handle thresholds, text conditions, and dimensional filters. KQL is the data source, not the rule engine
- Inline JSON in PowerShell `az rest --body` — PowerShell mangles quotes and special characters. Always write JSON to a temp file with
[System.IO.File]::WriteAllText($path, $json, [System.Text.UTF8Encoding]::new($false))and pass--body @$path - Reusing display names after deletion — soft-deleted items hold their name for several minutes. Use a unique name or hard-delete first
---
Examples
Follow the Assembly Procedure to build definitions. See reference docs for complete entity schemas: source-types.md, rule-conditions.md, action-types.md.
---
Agent Integration Notes
- This skill uses the Fabric Items API (
/reflexes) for CRUD and the Definition API for rule management - No additional data-plane protocols are needed — all operations use
az restwith the Fabric API audience - For reading Activator items and rules without modifying them, use the activator-consumption-cli skill instead
Activator Action Types — Rule Action Bindings
Complete reference for all supported action types that rules can trigger when conditions are met.
---
Where Actions Live
Actions appear in two places in ReflexEntities.json:
1. Inside a Rule's ActStep — the action binding (TeamsMessage, EmailMessage) is defined inline as a row in the ActStep 2. As a standalone entity — fabricItemAction-v1 entities define Fabric items (Pipelines, Notebooks, Spark jobs, Dataflows, Functions/UDFs) that rules can invoke
---
Action Types Summary
| Action | Kind (in ActStep) | Entity Type | Description |
|---|---|---|---|
| Teams Message | TeamsMessage | (inline in rule) | Send a Teams notification |
EmailMessage | (inline in rule) | Send an email | |
| Fabric Item | FabricItemInvocation | fabricItemAction-v1 | Execute a Pipeline, Notebook, Spark job, Dataflow, or Function/UDF |
Note: There is no dedicated "Power Automate flow" or "Custom endpoint/webhook" action type in the public definition API.
---
TeamsMessage
Sends a notification to Microsoft Teams. Recipients are specified by email address.
{
"name": "TeamsBinding",
"kind": "TeamsMessage",
"arguments": [
{ "name": "messageLocale", "type": "string", "value": "" },
{ "name": "recipients", "type": "array", "values": [
{ "type": "string", "value": "user@example.com" },
{ "type": "string", "value": "team-lead@example.com" }
]},
{ "name": "headline", "type": "array", "values": [
{ "type": "string", "value": "Alert headline text" }
]},
{ "name": "optionalMessage", "type": "array", "values": [
{ "type": "string", "value": "Detailed message body with context" }
]},
{ "name": "additionalInformation", "type": "array", "values": [] }
]
}| Argument | Type | Required | Description |
|---|---|---|---|
messageLocale | string | no | Language/locale (empty string for default) |
recipients | array of strings | yes | Email addresses of recipients |
headline | array of content parts | yes | Message title shown in Teams notification |
optionalMessage | array of content parts | no | Detailed message body |
additionalInformation | array | no | Extra context data |
TeamsMessage Design Guidance
- Multiple recipients receive independent notifications
- The
headlineshould be concise and actionable — it's the first thing users see - Use
optionalMessagefor context that helps the recipient understand and act on the alert - Inline dynamic content can be mixed into
headline/optionalMessageby embeddingAttributeReferenceparts directly in the field'svaluesarray - For inline message parts, use
{"kind":"AttributeReference","type":"complex","arguments":[...]}or{"kind":"EventFieldReference","type":"complex","arguments":[...]}— do not convert those inline parts tocomplexReference - For attribute-trigger rules, reference attributes by entity ID; for event-trigger rules, reference event fields by field name
- The
additionalInformationfield can include structured dynamic data viaNameReferencePair - Structured
additionalInformationuses nestedAttributeReference/EventFieldReferenceentries withtype: "complexReference"andname: "reference"
Working inline mixed-content example:
{
"name": "optionalMessage",
"type": "array",
"values": [
{ "name": "string", "type": "string", "value": "The humidity of this package has crossed above or below the allowed range." },
{
"kind": "AttributeReference",
"type": "complex",
"arguments": [{ "name": "entityId", "type": "string", "value": "<attr-id>" }]
},
{ "name": "string", "type": "string", "value": " " }
]
}Working event field message part:
{
"kind": "EventFieldReference",
"type": "complex",
"arguments": [
{ "name": "fieldName", "type": "string", "value": "Status" }
]
}Working additionalInformation example:
{
"kind": "NameReferencePair",
"type": "complex",
"arguments": [
{ "name": "name", "type": "string", "value": "Temperature" },
{
"name": "reference",
"kind": "AttributeReference",
"type": "complexReference",
"arguments": [
{ "name": "entityId", "type": "string", "value": "<temperature-attribute-guid>" }
]
}
]
}---
EmailMessage
Sends an email alert with configurable recipients (To, CC, BCC), subject, and body.
⚠️ Authoring guidance
>
In current backend behavior, authoring should use array-shaped content fields forsubject,headline,optionalMessage, andadditionalInformation, matching working readback and successful eval output.
{
"name": "EmailBinding",
"kind": "EmailMessage",
"arguments": [
{ "name": "messageLocale", "type": "string", "value": "en-us" },
{ "name": "sentTo", "type": "array", "values": [
{ "type": "string", "value": "primary@example.com" }
]},
{ "name": "copyTo", "type": "array", "values": [
{ "type": "string", "value": "manager@example.com" }
]},
{ "name": "bCCTo", "type": "array", "values": [] },
{ "name": "subject", "type": "array", "values": [
{ "type": "string", "value": "Alert: Sales threshold exceeded" }
]},
{ "name": "headline", "type": "array", "values": [
{ "type": "string", "value": "Main alert content displayed prominently" }
]},
{ "name": "optionalMessage", "type": "array", "values": [
{ "type": "string", "value": "Additional context and recommended actions" }
]},
{ "name": "additionalInformation", "type": "array", "values": [] }
]
}| Argument | Type | Required | Description |
|---|---|---|---|
messageLocale | string | no | e.g. en-us |
sentTo | array of strings | yes | Primary recipients (To) |
copyTo | array of strings | no | CC recipients |
bCCTo | array of strings | no | BCC recipients |
subject | array of content parts | yes | Email subject line |
headline | array of content parts | yes | Main content displayed prominently |
optionalMessage | array of content parts | no | Additional body text |
additionalInformation | array | no | Extra context |
EmailMessage vs TeamsMessage Differences
| Field | TeamsMessage | EmailMessage |
|---|---|---|
| Recipients | recipients (array) | sentTo + copyTo + bCCTo |
| Subject | N/A | subject (array) |
| Headline | array of content parts | array of content parts |
| Message | array of content parts | array of content parts |
---
Fabric Item Action (fabricItemAction-v1)
A standalone entity that defines a Fabric item (Pipeline, Notebook, Spark job, Dataflow, or Function/UDF) to execute when a rule fires. Rules reference this entity by uniqueIdentifier.
{
"uniqueIdentifier": "<fabric-item-action-guid>",
"payload": {
"name": "Run alert pipeline",
"fabricItem": {
"itemId": "<pipeline-item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "Pipeline"
},
"jobType": "Pipeline",
"parentContainer": {
"targetUniqueIdentifier": "<container-guid>"
}
},
"type": "fabricItemAction-v1"
}| Property | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name |
fabricItem.itemId | GUID | yes | Fabric item ID |
fabricItem.workspaceId | GUID | yes | Workspace containing the item |
fabricItem.itemType | string | yes | Pipeline, SynapseNotebook, SparkJobDefinition, DataflowFabric, UserDataFunctions, or FunctionSet |
jobType | string | yes | Job type (for example Pipeline, RunNotebook, sparkjob, or Execute) |
parentContainer.targetUniqueIdentifier | GUID | yes | Container ref |
Supported Fabric Item Types
| itemType | jobType | Description |
|---|---|---|
Pipeline | Pipeline | Run a Data Factory pipeline |
SynapseNotebook | RunNotebook | Run a Fabric notebook |
SparkJobDefinition | sparkjob | Run a Spark job definition |
DataflowFabric | Execute | Run a Dataflow |
UserDataFunctions | Execute | Run a user data function |
FunctionSet | Execute | Alias of UserDataFunctions; run a function from a function set |
⚠️ Notebooks use `itemType: "SynapseNotebook"` with `jobType: "RunNotebook"` (not"Notebook"or"SparkJob").
>
⚠️ `FunctionSet` is handled as an alias of `UserDataFunctions` in backend execution.
>
⚠️ The public Fabric items API exposes the underlying item type as `UserDataFunction` (singular), but Activator action payloads still use `itemType: "UserDataFunctions"` (plural).
>
⚠️ Readback nuance for UDF / function-set actions: on write/import, authoring commonly usesUserDataFunctions. On a latergetDefinitionreadback, the standalonefabricItemAction-v1entity may normalizepayload.fabricItem.itemTypetoFunctionSet, while the rule's embeddedFabricItemBinding.arguments.itemTypestill remainsUserDataFunctions.
>
⚠️ UDF prerequisite: before wiring a UDF action, verify the target UserDataFunction item exposes the function you plan to call. If the item has no registered functions, fix the UDF definition first; do not treat the Activator action as valid.Target-Specific fabricItemAction-v1 Examples
Notebook
{
"uniqueIdentifier": "<notebook-action-guid>",
"payload": {
"name": "Run alert notebook",
"fabricItem": {
"itemId": "<notebook-item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "SynapseNotebook"
},
"jobType": "RunNotebook",
"parentContainer": {
"targetUniqueIdentifier": "<container-guid>"
}
},
"type": "fabricItemAction-v1"
}Spark Job Definition
{
"uniqueIdentifier": "<spark-job-action-guid>",
"payload": {
"name": "Run alert spark job",
"fabricItem": {
"itemId": "<spark-job-item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "SparkJobDefinition"
},
"jobType": "sparkjob",
"parentContainer": {
"targetUniqueIdentifier": "<container-guid>"
}
},
"type": "fabricItemAction-v1"
}Dataflow
{
"uniqueIdentifier": "<dataflow-action-guid>",
"payload": {
"name": "Run alert dataflow",
"fabricItem": {
"itemId": "<dataflow-item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "DataflowFabric"
},
"jobType": "Execute",
"parentContainer": {
"targetUniqueIdentifier": "<container-guid>"
}
},
"type": "fabricItemAction-v1"
}User Data Function / Function Set
{
"uniqueIdentifier": "<udf-action-guid>",
"payload": {
"name": "Run alert function",
"fabricItem": {
"itemId": "<udf-item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "UserDataFunctions"
},
"jobType": "Execute",
"parentContainer": {
"targetUniqueIdentifier": "<container-guid>"
}
},
"type": "fabricItemAction-v1"
}How Rules Reference Fabric Item Actions
The ActStep uses a FabricItemBinding row with kind FabricItemInvocation. This is the same structure in both AttributeTrigger and EventTrigger — the ActStep grammar is identical across all trigger types.
All 7 base arguments are required (including empty arrays). Some item types add more arguments; for example UDF / Function Set bindings add subitemId.
Use a template version that supports every argument in the binding. Parameters require at least 1.2, and flexible item types / UDF subitemId require at least 1.2.3; the default rule template version 1.2.4 covers these known requirements.
Set fabricJobConnectionDocumentId to the uniqueIdentifier of the standalone fabricItemAction-v1 entity. The backend treats that value as the reference from the rule binding row to the action document; do not replace it with the Fabric item ID.
For Spark Job Definition ActStep bindings, use itemType: "SparkJobDefinition". The exact jobType value is backend-passed-through; prefer a known-good payload/readback for the target environment instead of guessing.
{
"name": "FabricItemBinding",
"kind": "FabricItemInvocation",
"arguments": [
{ "name": "workspaceId", "type": "string", "value": "<workspace-guid>" },
{ "name": "itemId", "type": "string", "value": "<pipeline-or-notebook-guid>" },
{ "name": "itemType", "type": "string", "value": "Pipeline" },
{ "name": "jobType", "type": "string", "value": "Pipeline" },
{ "name": "fabricJobConnectionDocumentId", "type": "string", "value": "<fabric-item-action-guid>" },
{ "name": "additionalInformation", "type": "array", "values": [] },
{ "name": "parameters", "type": "array", "values": [] }
]
}⚠️ Common mistakes that cause `RowCountMismatch`:
1. Missing arguments — all 7 base arguments are required, includingadditionalInformationandparametersas empty arrays
2. Wrong row name — must be"FabricItemBinding"(not"FabricItemInvocation"— that's thekind)
3. Multiple rows in ActStep — ActStep allows exactly ONE action binding row
For UserDataFunctions and FunctionSet, include a subitemId string argument in the binding to name the specific function to execute. Match the binding's parameterName values to the names exposed by the Fabric function metadata, and use Activator's canonical `parameterType` values — String, Number, or Boolean — for each parameter. The Fabric function metadata may surface Python type names such as str, float, or int; do not pass those through as parameterType on the binding — the rule validator rejects them. Map them to the canonical Activator types instead:
Fabric function metadata dataType | Activator binding parameterType |
|---|---|
str | String |
int, float | Number |
bool | Boolean |
Recommended authoring pattern: keep the bindingitemTypeasUserDataFunctionseven if a later readback shows the standalone action entity asFunctionSet.
>
Linkage prerequisite: subitemId must match a real function exposed by the target User Data Function item. If the item exists but exposes no functions, fix the UDF definition first; the Activator linkage is not valid until a function is registered.For dynamic parameter values inside FabricItemParameter.parameterValue, use reference-valued parts with type: "complexReference". This differs from inline Teams headline / optionalMessage fragments, where type: "complex" is correct.
{
"name": "FabricItemBinding",
"kind": "FabricItemInvocation",
"arguments": [
{ "name": "workspaceId", "type": "string", "value": "<workspace-guid>" },
{ "name": "itemId", "type": "string", "value": "<function-set-guid>" },
{ "name": "itemType", "type": "string", "value": "UserDataFunctions" },
{ "name": "jobType", "type": "string", "value": "Execute" },
{ "name": "fabricJobConnectionDocumentId", "type": "string", "value": "<udf-action-guid>" },
{ "name": "additionalInformation", "type": "array", "values": [] },
{ "name": "parameters", "type": "array", "values": [
{
"kind": "FabricItemParameter",
"type": "complex",
"arguments": [
{ "name": "parameterName", "type": "string", "value": "name" },
{ "name": "parameterType", "type": "string", "value": "String" },
{ "name": "parameterValue", "type": "complexArray", "values": [
{ "type": "string", "value": "world" }
]}
]
},
{
"kind": "FabricItemParameter",
"type": "complex",
"arguments": [
{ "name": "parameterName", "type": "string", "value": "temperature" },
{ "name": "parameterType", "type": "string", "value": "Number" },
{ "name": "parameterValue", "type": "complexArray", "values": [
{
"kind": "AttributeReference",
"type": "complexReference",
"arguments": [
{ "name": "entityId", "type": "string", "value": "<temperature-attribute-guid>" }
]
}
]}
]
}
]},
{ "name": "subitemId", "type": "string", "value": "<published-function-name>" }
]
}Additional gotchas for dynamic FabricItemParameter values
The worked UDF binding example above covers the canonical static + dynamic pattern. A few additional gotchas are worth calling out explicitly because they each produced a 400 with a misleading error pointed at the leaf rule rather than the offending field:
Envelope contrast — same AttributeReference, two shapes
AttributeReference appears in several places inside the rule graph, and the envelope differs by location. Reuse the wrong shape and you get a 400. The two shapes you will see in the same definition:
| Where it appears | Envelope |
|---|---|
Inside ScalarSelectStep / DimensionalFilterStep rows | { "kind": "AttributeReference", "type": "complex", "name": "attribute", "arguments": [...] } |
Inside FabricItemParameter.parameterValue.values | { "kind": "AttributeReference", "type": "complexReference", "arguments": [...] } (no name field) |
For the structured additionalInformation form used by Teams / Email actions, see the TeamsMessage guidance further up — that one uses type: "complexReference" with name: "reference", which is yet a different envelope.
AttributeReference.entityId must point at a BasicEventAttribute
Inside FabricItemParameter.parameterValue, the AttributeReference.entityId must resolve to a BasicEventAttribute entity in the same definition. Pointing at an IdentityPartAttribute returns 400 Invalid TimeSeriesView payload. with no hint about the template type. If you want to pass an identity field dynamically, declare a parallel BasicEventAttribute over the same source field and reference that.
Backend Execution Payload Shapes
The runtime request body sent to the Fabric jobs endpoint depends on itemType:
Notebook (SynapseNotebook)
{
"ExecutionData": {
"Parameters": {
"name": { "value": 345.13, "type": "float" },
"isName": { "value": true, "type": "bool" },
"NotebookName": { "value": "MyNotebook", "type": "string" }
}
}
}Spark Job Definition (SparkJobDefinition)
{
"ExecutionData": {
"mainClass": "com.microsoft.spark.example.OnePlusOneApp",
"executableFile": "abfss://workspace@onelake.dfs.fabric.microsoft.com/lakehouse.Lakehouse/Files/job.jar",
"commandLineArguments": "--input bronze --output silver"
}
}Spark job definitions are schema-supported, but current backend parameter discovery returns no user-defined parameters. Use explicit parameter names likemainClass,executableFile, andcommandLineArguments.
Dataflow (DataflowFabric)
{
"ExecutionData": {
"ExecuteOption": "ApplyChangesIfNeeded",
"Parameters": [
{ "parameterName": "Threshold", "type": "Automatic", "value": 25 },
{ "parameterName": "Mode", "type": "Automatic", "value": "Incremental" }
]
}
}User Data Function / Function Set (UserDataFunctions / FunctionSet)
{
"ExecutionData": {
"FunctionName": "hello_fabric",
"Parameters": {
"name": "world"
},
"RunKind": "Activator",
"RelatedArtifacts": "<activator-artifact-guid>"
}
}Fabric Item Action Design Guidance
- The target Fabric item must already exist in the target workspace
- Resolve
itemIdandworkspaceIddynamically via the Fabric Items API — do not hardcode - The Activator's managed identity must have permissions to execute the target item
- Pipeline, notebook, dataflow, Spark job, and function actions can all pass parameters from the triggering event, but the runtime payload shape differs by item type
Digital Twin Builder / Ontology Source (digitalTwinBuilderSource-v1)
Queries an existing Digital Twin Builder or Ontology Fabric item on a schedule and feeds the returned rows into the Activator pipeline.
Important: query.queryString is not KQL. It is a JSON-string payload that Activator later POSTs to the DTB query endpoint.Time-axis default: If the DTB query results include a reasonable datetime field, prefereventTimeSettingsplusDURATION_START/DURATION_ENDquery parameters. Only use snapshot mode when the query returns current-state rows with no reasonable event-time field.
Validate first: Before creating or updating the Activator, run the DTB / Ontology query directly first and confirm the returned columns, key fields, and timestamp field are correct.
{
"uniqueIdentifier": "<dtb-source-guid>",
"payload": {
"name": "Truck telemetry from ontology",
"runSettings": {
"executionIntervalInSeconds": 300
},
"query": {
"queryString": "{\"entitySelector\":{\"query\":\"MATCH [t:Truck] RETURN t.id as TruckId, t.site as Site\"},\"timeSeriesSelector\":{\"entityType\":{\"Name\":\"Truck\"},\"keyColumns\":{\"id\":\"TruckId\"},\"metrics\":[{\"field\":\"velocity\"},{\"field\":\"temperature\"}],\"groupBy\":[\"TruckId\",\"Site\"]}}",
"compositeKey": {
"name": "dtbCompositeKey",
"keys": ["TruckId", "Site"]
}
},
"connection": {
"itemId": "<ontology-or-dtb-item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "Ontology"
},
"queryParameters": [
{ "name": "start", "type": "DURATION_START", "value": "2025-09-04T19:00:00Z" },
{ "name": "end", "type": "DURATION_END", "value": "2025-09-04T19:20:00Z" }
],
"eventTimeSettings": {
"timeFieldName": "Timestamp",
"ingestionDelayInSeconds": 120
},
"metadata": {
"digitalTwinBuilderEntityId": "Truck"
},
"parentContainer": {
"targetUniqueIdentifier": "<container-guid>"
}
},
"type": "digitalTwinBuilderSource-v1"
}| Property | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name |
runSettings.executionIntervalInSeconds | integer | yes | Poll frequency in seconds. Schema range: 60-86400 |
query.queryString | string | yes | JSON-string query payload sent to the DTB endpoint |
query.compositeKey.name | string | no | Display name for a generated composite key column |
query.compositeKey.keys[] | string[] | no | Column names to concatenate into the composite key |
connection.itemId | GUID | yes | Target Digital Twin Builder / Ontology item ID |
connection.workspaceId | GUID | yes | Workspace containing that item |
connection.itemType | string | yes | Either "DigitalTwinBuilder" or "Ontology" |
queryParameters | array | no | Optional query params. Use DURATION_START / DURATION_END for time-axis mode |
eventTimeSettings.timeFieldName | string | no | Event-time field in the returned rows |
eventTimeSettings.ingestionDelayInSeconds | integer | no | Late-arrival buffer in seconds |
metadata.digitalTwinBuilderEntityId | string | no | Optional DTB entity identifier. If metadata is present, this field is required |
parentContainer.targetUniqueIdentifier | GUID | yes | Container ref |
---
connection Item Types
The DTB source can point at either supported item kind:
{
"connection": {
"itemId": "<item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "DigitalTwinBuilder"
}
}{
"connection": {
"itemId": "<item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "Ontology"
}
}Use the actual item type returned by the Fabric Items API when you resolve the target item dynamically.
Query Payload Pattern
query.queryString stores a JSON object as a string. The backend test coverage shows this general shape:
{
"entitySelector": {
"query": "MATCH [t:Truck] RETURN t.id as TruckId, t.color as Color"
},
"timeSeriesSelector": {
"entityType": { "Name": "Truck" },
"keyColumns": { "id": "TruckId" },
"metrics": [{ "field": "velocity" }],
"groupBy": ["TruckId"]
}
}Common authoring notes:
- Build that object in Python, then serialize it with
json.dumps(...) - Store the serialized string in
query.queryString - Do not embed the object directly as nested JSON inside
ReflexEntities.json - Use
query.compositeKeywhen the returned rows need a stable synthetic identity built from multiple columns
Design Guidance
- Resolve the backing Fabric item dynamically by name and type, then use its
itemId,workspaceId, and actualitemType - Prefer Ontology when the source is an ontology item; prefer DigitalTwinBuilder when the source is the DTB item itself
- Keep the DTB query focused on data retrieval and shaping; let the Activator rule handle thresholds, text conditions, and filtering logic
- Use
query.compositeKeywhen identity depends on multiple returned fields - If
metadatais included, it must containdigitalTwinBuilderEntityId
---
Time-Axis Mode
Use time-axis mode when the DTB result rows include a reasonable datetime field.
{
"queryParameters": [
{ "name": "start", "type": "DURATION_START", "value": "2025-09-04T19:00:00Z" },
{ "name": "end", "type": "DURATION_END", "value": "2025-09-04T19:20:00Z" }
],
"eventTimeSettings": {
"timeFieldName": "Timestamp",
"ingestionDelayInSeconds": 120
}
}Important difference from KQL
For KQL sources, the duration parameters are referenced inside the KQL text. For DTB sources, the backend appends them as URL query-string parameters when calling the DTB endpoint. The query payload itself stays as the JSON-string body.
Backend examples use start and end, which are good names to mirror in authored payloads. Even though the executor can fall back to default names, do not rely on that fallback in authored definitions.
Snapshot Mode
Use snapshot mode when the DTB query returns the latest state and there is no reliable event-time field.
{
"payload": {
"name": "Truck inventory snapshot",
"runSettings": {
"executionIntervalInSeconds": 300
},
"query": {
"queryString": "{\"entitySelector\":{\"query\":\"MATCH [t:Truck] RETURN t.id as TruckId, t.state as State, t.battery as BatteryLevel\"}}"
},
"connection": {
"itemId": "<dtb-item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "DigitalTwinBuilder"
},
"queryParameters": [],
"parentContainer": {
"targetUniqueIdentifier": "<container-guid>"
}
}
}Snapshot-mode guidance:
- omit
eventTimeSettings - set
queryParametersto[]unless the endpoint genuinely needs stableHARDCODEDparameters - do not model rolling time windows when the source has no trustworthy timestamp field
Backend Notes
The full stored DTB source document also contains service-managed fields such as:
system.metadata.internalEventNamesystem.metadata.initialDigitalTwinBuilderCapacityIdsystem.connection.connectionStringsystem.connection.authMethod
Those fields matter for backend execution and readback, but the main authoring task is to construct the correct entity payload shown above.
Activator Eventstream Source — Sink-First Push Workflow
Eventstream is a push source for Activator. Do not start by hand-authoring a full eventstreamSource-v1 entity in ReflexEntities.json.
Instead, the supported workflow is:
1. create or identify the target Activator 2. create or update an Eventstream with an Activator destination pointing at that Activator 3. read the Activator definition back 4. find the auto-created Eventstream source and SourceEvent entities 5. add the rest of the trigger graph by referencing that discovered SourceEvent
Eventstream-side topology shape
The Eventstream destination is authored on the Eventstream side, not inside ReflexEntities.json:
{
"name": "ActivatorDest",
"type": "Activator",
"properties": {
"workspaceId": "<activator-workspace-guid>",
"itemId": "<activator-item-guid>",
"inputSerialization": {
"type": "Json",
"properties": { "encoding": "UTF8" }
}
},
"inputNodes": [{ "name": "MainStream" }]
}Minimal topology:
{
"sources": [
{
"name": "SampleSource",
"type": "SampleData",
"properties": { "type": "Bicycles" }
}
],
"streams": [
{
"name": "MainStream",
"type": "DefaultStream",
"properties": {},
"inputNodes": [{ "name": "SampleSource" }]
}
],
"destinations": [
{
"name": "ActivatorDest",
"type": "Activator",
"properties": {
"workspaceId": "<activator-workspace-guid>",
"itemId": "<activator-item-guid>",
"inputSerialization": {
"type": "Json",
"properties": { "encoding": "UTF8" }
}
},
"inputNodes": [{ "name": "MainStream" }]
}
],
"operators": [],
"compatibilityLevel": "1.1"
}Activator readback after sink creation
After the Eventstream sink is created, the target Activator definition auto-created:
1. one eventstreamSource-v1 2. one timeSeriesView-v1 event view (SourceEvent) that references that source
Auto-created eventstreamSource-v1
{
"uniqueIdentifier": "<eventstream-source-guid>",
"payload": {
"name": "EventStream",
"metadata": {
"eventstreamArtifactId": "<eventstream-item-guid>"
}
},
"type": "eventstreamSource-v1"
}Auto-created SourceEvent view
{
"uniqueIdentifier": "<source-event-guid>",
"payload": {
"name": "<eventstream-display-name>-stream",
"definition": {
"type": "Event",
"instance": "{\"templateId\":\"SourceEvent\",\"templateVersion\":\"1.1\",\"steps\":[{\"name\":\"SourceEventStep\",\"id\":\"<guid>\",\"rows\":[{\"name\":\"SourceSelector\",\"kind\":\"SourceReference\",\"arguments\":[{\"name\":\"entityId\",\"type\":\"string\",\"value\":\"<eventstream-source-guid>\"}]}]}]}"
}
},
"type": "timeSeriesView-v1"
}Readback notes
payload.metadata.eventstreamArtifactIdmatched the Eventstream item ID from the Eventstream item API.- The auto-created SourceEvent
SourceSelector.entityIdpointed at the auto-createdeventstreamSource-v1.uniqueIdentifier. - The Eventstream destination node ID from Eventstream topology can match the
eventstreamSource-v1.uniqueIdentifierseen in Activator readback. - The auto-created Eventstream source and SourceEvent did not include explicit
parentContainerfields in public readback. - When appending rules to an Eventstream sink-created Activator, preserve missing
parentContainerfields on the auto-created source/event entities. Do not invent a container unless you are adding a consistent container graph for every related entity.
Treat the destination-ID-to-source-ID match as a useful readback clue, not as an authoring input you set manually.
Building the rest of the trigger graph
Once the sink has created the source entities:
1. call getDefinition 2. find the timeSeriesView-v1 event view whose definition.type is Event 3. use that SourceEvent entity ID wherever the rule graph expects the upstream event reference 4. build the remaining rule and action entities using the general rule guidance for this skill 5. use the general rule template-version guidance for newly appended rules; do not downgrade a new rule just because an auto-created SourceEvent readback used an older version 6. to add a disabled rule, keep the rule entity lifecycle published and set payload.definition.settings.shouldRun: false; do not represent disabled state by changing lifecycle or by changing the auto-created source graph
When to use Eventstream vs other Activator sources
Use Eventstream when:
- the upstream source is already modeled as an Eventstream topology
- data arrives continuously and should be pushed into Activator
- you want Activator to react to Eventstream sample data, CDC feeds, or Eventstream-connected services
Prefer KQL / DTB / Real-time Hub when:
- the scenario is naturally pull-based
- you can author the source completely inside
ReflexEntities.json - there is no Eventstream sink step involved
KQL Source (kqlSource-v1)
Queries a KQL database (Eventhouse or ADX/Kusto cluster) on a configurable schedule. The query runs periodically and feeds results into the Activator pipeline.
Design principle: The KQL query should return ALL relevant data — do NOT pre-filter for the condition in KQL. Let the Activator rule handle the detection logic (thresholds, text conditions, etc.) via its steps. The KQL query is just the data source.
Time-axis default: If the query results include a reasonable datetime column, always configureeventTimeSettingsandqueryParametersso the source runs with a time axis. Only fall back to snapshot mode when the underlying data has no reasonable timestamp column and each row represents the latest state.
Validate first: Before creating or updating the Activator, run the KQL directly against the target KQL source and confirm the returned columns, timestamp field, and row shape are correct.
{
"uniqueIdentifier": "<kql-source-guid>",
"payload": {
"name": "Sensor telemetry query",
"runSettings": {
"executionIntervalInSeconds": 60
},
"query": {
"queryString": "declare query_parameters(startTime:datetime, endTime:datetime);\nSensorData | where Timestamp between (startTime .. endTime) | project Timestamp, DeviceId, Temperature, Building"
},
"eventhouseItem": {
"itemId": "<kql-database-item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "KustoDatabase"
},
"queryParameters": [
{ "name": "startTime", "type": "DURATION_START", "value": "2025-01-01T00:00:00Z" },
{ "name": "endTime", "type": "DURATION_END", "value": "2025-01-01T00:05:00Z" }
],
"eventTimeSettings": {
"timeFieldName": "Timestamp",
"ingestionDelayInSeconds": 120,
"timeZone": "UTC"
},
"metadata": {
"workspaceId": "<workspace-guid>",
"measureName": "",
"querySetId": "",
"queryId": ""
},
"parentContainer": {
"targetUniqueIdentifier": "<container-guid>"
}
},
"type": "kqlSource-v1"
}| Property | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name |
runSettings.executionIntervalInSeconds | number | yes | Poll frequency in seconds |
query.queryString | string | yes | KQL query to execute |
eventhouseItem.itemId | GUID | yes | KQL Database item ID (not the Eventhouse ID) |
eventhouseItem.workspaceId | GUID | yes | Workspace containing the KQL Database |
eventhouseItem.itemType | string | yes | Always "KustoDatabase" |
queryParameters | array | yes | Query parameters — usually DURATION_START/DURATION_END; use empty [] only for snapshot mode |
metadata.workspaceId | GUID | yes | Workspace ID (same as eventhouseItem.workspaceId) |
metadata.measureName | string | yes | Usually empty string "" |
metadata.querySetId | string | yes | Usually empty string "" |
metadata.queryId | string | yes | Usually empty string "" |
eventTimeSettings | object | no | Time-axis configuration — expected whenever the query results include a reasonable timestamp |
parentContainer.targetUniqueIdentifier | GUID | yes | Container ref |
---
eventhouseItem Reference Shapes
eventhouseItem is a union in the schema. Use one of these two shapes:
1. Fabric Eventhouse / KQL Database reference
Use this when the source is a Fabric KQL database item:
{
"eventhouseItem": {
"itemId": "<kql-database-item-guid>",
"workspaceId": "<workspace-guid>",
"itemType": "KustoDatabase"
}
}2. External ADX / Kusto cluster reference
Use this when the source is an external ADX/Kusto cluster instead of a Fabric item:
{
"eventhouseItem": {
"clusterHostName": "mycluster.westeurope.kusto.windows.net",
"databaseName": "MyDatabase"
}
}Exact schema field names: the ADX reference usesclusterHostNameanddatabaseName. It is notclusterUrl.
Design Guidance
- Do NOT pre-filter conditions in KQL — return all data and let the Activator rule handle detection logic (thresholds, text conditions, filters). The KQL query should only select the relevant time window and project the needed columns
- For Fabric sources,
eventhouseItem.itemIdis the KQL Database item ID (not the Eventhouse ID) — resolve via the Fabric Items API (GET /v1/workspaces/{wsId}/kqlDatabases) - For ADX/Kusto sources, use
eventhouseItem.clusterHostNameandeventhouseItem.databaseName - The
queryParametersandmetadatafields are required even if empty - Default to time-axis mode when the query results contain a reasonable datetime column
- Use snapshot mode only when there is no reasonable timestamp column and the rows represent current state, not an event stream
---
Time-Axis Default (eventTimeSettings)
If the query results have a usable datetime column, use eventTimeSettings plus queryParameters. This is the default mode for KQL sources because it gives Activator an explicit event-time axis, watermark tracking, and late-arrival handling.
Choose the Mode
| Mode | When to Use |
|---|---|
| Time-axis mode | The query results include a reasonable datetime column that represents when each row/event happened |
| Snapshot mode | The source has no reasonable timestamp column and each row represents the latest state of an entity |
Configuration
Add eventTimeSettings and queryParameters to the kqlSource payload for the normal time-axis case:
{
"query": {
"queryString": "declare query_parameters(startTime:datetime, endTime:datetime);\nMyTable | where Timestamp between (startTime .. endTime) | project Timestamp, DeviceId, Temperature"
},
"eventTimeSettings": {
"timeFieldName": "Timestamp",
"ingestionDelayInSeconds": 120,
"timeZone": "UTC"
},
"queryParameters": [
{ "name": "startTime", "type": "DURATION_START", "value": "2025-01-01T00:00:00Z" },
{ "name": "endTime", "type": "DURATION_END", "value": "2025-01-01T00:05:00Z" }
]
}eventTimeSettings Fields
| Field | Type | Required | Description |
|---|---|---|---|
timeFieldName | string | yes | The datetime column in query results used as the time axis. After each execution, the max value of this column becomes the watermark for the next query. |
ingestionDelayInSeconds | number | no | Late-arrival buffer in seconds. Shifts the query end-time back from "now" by this amount, ensuring late-arriving data is not missed. Default: 0. |
timeZone | string | no | Time zone for interpretation. Currently only "UTC" is supported. |
queryParameters with Time-Axis
When eventTimeSettings is set, queryParameters must include one DURATION_START and one DURATION_END entry. The KQL itself must also declare those parameters with declare query_parameters(startTime:datetime, endTime:datetime); before the query body.
| Field | Type | Description |
|---|---|---|
name | string | Parameter name referenced in the KQL query (e.g., startTime) |
type | string | "DURATION_START" or "DURATION_END" |
value | string | Initial value (ISO 8601) — defines the backfill window on first execution |
How Execution Works
1. First execution: Query runs with the value from each parameter to determine the initial data window 2. Subsequent executions: DURATION_START is automatically overridden with the watermark (max event time from previous results). DURATION_END is overridden with now - ingestionDelayInSeconds
KQL Query Pattern for Time-Axis
Use declare query_parameters(...) followed by between with the parameter names:
declare query_parameters(startTime:datetime, endTime:datetime);
MyTable
| where Timestamp between (startTime .. endTime)
| project Timestamp, DeviceId, Temperature, BuildingDo not use ago() as the normal pattern for KQL sources. If there is a usable timestamp column, model it explicitly with eventTimeSettings.
Snapshot Mode (No Reasonable Timestamp Column)
Use snapshot mode only when there is no reasonable timestamp column and each row is the current state of an entity. In that case:
- Omit
eventTimeSettings - Set
queryParametersto[] - Do not add
ago(),between, or other time filtering - Project the current-state columns the rule needs
DeviceInventory
| project DeviceId, DeviceName, Status, Location, BatteryLevelReal-time Hub Source (realTimeHubSource-v1)
Monitors Fabric workspace events. Useful for governance and operational alerting — e.g., notifying when items are created, updated, or deleted.
Use a Real-Time Hub subscriptions container for workspace-event subscriptions:
{
"uniqueIdentifier": "<container-guid>",
"payload": {
"name": "eval-workspace-monitor",
"type": "rthSubscriptions"
},
"type": "container-v1"
}{
"uniqueIdentifier": "<rthub-source-guid>",
"payload": {
"name": "Workspace event monitor",
"connection": {
"scope": "Workspace",
"tenantId": "<tenant-guid>",
"workspaceId": "<workspace-guid>",
"eventGroupType": "Microsoft.Fabric.WorkspaceEvents"
},
"filterSettings": {
"eventTypes": [
{ "name": "Microsoft.Fabric.ItemCreateSucceeded" },
{ "name": "Microsoft.Fabric.ItemUpdateSucceeded" }
],
"filters": []
},
"parentContainer": {
"targetUniqueIdentifier": "<container-guid>"
}
},
"type": "realTimeHubSource-v1"
}| Property | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name |
connection.scope | string | yes | e.g. Workspace |
connection.tenantId | GUID | yes | Azure tenant ID |
connection.workspaceId | GUID | yes | Fabric workspace ID |
connection.eventGroupType | string | yes | e.g. Microsoft.Fabric.WorkspaceEvents |
filterSettings.eventTypes[].name | string | yes | Event type names to monitor |
filterSettings.filters | array | no | Additional filters |
parentContainer.targetUniqueIdentifier | GUID | yes | Container ref |
referenced container payload.type | string | yes | Use rthSubscriptions for Real-Time Hub workspace subscriptions |
Required Workspace-Events Connection Shape
For Fabric workspace events, include all of these connection fields together:
{
"scope": "Workspace",
"tenantId": "<tenant-guid>",
"workspaceId": "<workspace-guid>",
"eventGroupType": "Microsoft.Fabric.WorkspaceEvents"
}Do not use ad-hoc container types such as workspaceEvents for this graph. Backend Real-Time Hub subscription builders use the RthSubscriptions enum, which serializes in Reflex definitions as rthSubscriptions.
Authoring caveat: Fabric workspace-event subscriptions are normally provisioned through the OneRiver / Real-Time Hub subscription flow before the Activator definition is persisted. If a hand-authoredrealTimeHubSource-v1payload is rejected byupdateDefinitionwithInvalid definition, do not keep adding Object / SplitEvent / Attribute scaffolding. Treat the source as requiring a known-good Real-Time Hub/onramp-created readback shape or a pre-created workspace-events fixture, then preserve that source graph when adding or updating rules.
Supported Workspace Event Types
| Event Type | Description |
|---|---|
Microsoft.Fabric.ItemCreateSucceeded | An item was created |
Microsoft.Fabric.ItemCreateFailed | An item creation failed |
Microsoft.Fabric.ItemUpdateSucceeded | An item was updated |
Microsoft.Fabric.ItemUpdateFailed | An item update failed |
Microsoft.Fabric.ItemDeleteSucceeded | An item was deleted |
Microsoft.Fabric.ItemDeleteFailed | An item deletion failed |
Microsoft.Fabric.ItemReadSucceededandMicrosoft.Fabric.ItemReadFailedwere retired for new subscriptions on 2025-03-21 and should not be used in new definitions.
Event Payload Notes
- The event type tells you the lifecycle operation (
create,update,delete,succeeded,failed) - The event payload carries the changed artifact in
data.itemKind,data.itemId,data.itemName,data.workspaceId, anddata.workspaceName - Artifact-specific differentiation is by
itemKind, not by separate event type families
Known Item-Kind Limitation
The official docs say Fabric workspace item events currently do not support these Power BI item kinds:
- Semantic Model
- Paginated report
- Report
- App
- Dashboard
Activator Rule Conditions — timeSeriesView-v1 Templates & Rule Logic
⚠️ Every template-backed `timeSeriesView-v1` entity MUST be wrapped in a `timeSeriesView-v1` entity envelope with the template JSON.stringify'd into definition.instance. Never output a raw template — always output the full entity.---
This reference covers the template-backed `timeSeriesView-v1` entities used in Activator definitions:
- Rule views (
definition.type = "Rule") - Event views such as
SourceEventandSplitEvent(definition.type = "Event") - Attribute views such as
IdentityPartAttributeandBasicEventAttribute(definition.type = "Attribute")
Rules are the main focus because this file explains condition rows, detectors, aggregation, occurrence options, and actions, but the same timeSeriesView-v1 envelope and template conventions also apply to the other view types listed below.
Rule view entity envelope
Rules are timeSeriesView-v1 entities with definition.type = "Rule":
{
"uniqueIdentifier": "<guid>",
"payload": {
"name": "Too hot for medicine",
"description": "Created by: skills-for-fabric",
"parentObject": { "targetUniqueIdentifier": "<object-guid>" },
"parentContainer": { "targetUniqueIdentifier": "<container-guid>" },
"definition": {
"type": "Rule",
"instance": "<JSON-encoded template — MUST be a string, not nested object>",
"settings": { "shouldRun": true, "shouldApplyRuleOnUpdate": false }
}
},
"type": "timeSeriesView-v1"
}Critical:definition.instanceis a JSON-encoded string. You mustJSON.stringify()the template object and set it as a string value, not a nested object.
For user clarity, add payload.description: "Created by: skills-for-fabric" to rule entities.
Settings: shouldRun (boolean — is rule active), shouldApplyRuleOnUpdate (boolean — re-evaluate on definition update).
Default new rules to shouldRun: true so they start in the started / running state. Use shouldRun: false only when the user explicitly wants a stopped rule or when a safe verification workflow intentionally requires a disabled rule.
---
Rule Template Structure
Template version: Default newly authored rules to1.2.4unless backend guidance or a known-good readback requires a newer version. Features such as Fabric item parameters require at least1.2, and flexible item types / UDFsubitemIdrequire at least1.2.3, so1.2.4covers the known public requirements. When modifying an existing source-created graph, preserve the existing template shape unless the new rows require a newer version.
{ "templateId": "AttributeTrigger", "templateVersion": "1.2.4",
"steps": [
{ "name": "ScalarSelectStep", "id": "<guid>", "rows": [...] },
{ "name": "ScalarDetectStep", "id": "<guid>", "rows": [...] },
{ "name": "DimensionalFilterStep", "id": "<guid>", "rows": [...] },
{ "name": "ActStep", "id": "<guid>", "rows": [...] }
]
}Template IDs
| templateId | Used For | Step Sequence |
|---|---|---|
AttributeTrigger | Rule views | ScalarSelectStep → ScalarDetectStep → (DimensionalFilterStep)* → ActStep |
EventTrigger | Rule views | FieldsDefaultsStep → (EventDetectStep)+ → (DimensionalFilterStep)* → ActStep |
SourceEvent | Event views | SourceEventStep |
SplitEvent | Event views | SplitEventStep |
IdentityPartAttribute | Attribute views | IdPartStep |
BasicEventAttribute | Attribute views | EventSelectStep → EventComputeStep |
Step Sequence Notation
*means zero or more+means one or more
Minimal EventTrigger Entity Graph
For pure event-trigger scenarios, the minimal valid graph is:
Container -> Source -> SourceEvent -> Rule
\
-> (optional) fabricItemAction-v1Do not add Object, SplitEvent, IdentityPartAttribute, or BasicEventAttribute entities unless you are intentionally switching to attribute-based modeling.
EventDetectStep Branches
Use exactly ONE branch per step:
| Branch | Rows | Use Case |
|---|---|---|
EventHeartbeatDetector | OnEveryValue or NoHeartbeat alone | Fire on every event, or detect missing events |
EventStateDetector | EventFieldSelector + state condition | Fire when event field meets condition |
EventChangeDetector | EventFieldSelector + change condition | Fire when event field changes |
OnEveryValue:
{ "name": "EventDetectStep", "id": "<guid>",
"rows": [{ "name": "OnEveryValue", "kind": "OnEveryValue", "arguments": [] }] }NoHeartbeat (fire when events STOP — e.g., 5min = 300000ms):
{ "name": "EventDetectStep", "id": "<guid>",
"rows": [{ "name": "NoHeartbeat", "kind": "NoHeartbeat",
"arguments": [{ "name": "duration", "type": "timeSpan", "value": 300000 }] }] }EventStateDetector (field + state condition):
{ "name": "EventDetectStep", "id": "<guid>",
"rows": [
{ "name": "EventFieldSelector", "kind": "EventField",
"arguments": [{ "name": "fieldName", "type": "string", "value": "severity" }] },
{ "name": "TextValueCondition", "kind": "TextValueCondition",
"arguments": [
{ "name": "op", "type": "string", "value": "IsEqualTo" },
{ "name": "value", "type": "string", "value": "Error" }] }
] }State conditions: NumberValueCondition, NumberRangeCondition, TextValueCondition, TextLengthCondition, LogicalValueCondition.
EventChangeDetector (field + change condition):
{ "name": "EventDetectStep", "id": "<guid>",
"rows": [
{ "name": "EventFieldSelector", "kind": "EventField",
"arguments": [{ "name": "fieldName", "type": "string", "value": "status" }] },
{ "name": "AnyValueChange", "kind": "AnyValueChange",
"arguments": [{ "name": "op", "type": "string", "value": "Changes" }] }
] }Change conditions: NumberBecomes, NumberEntersOrLeavesRange, NumberChanges, NumberTrendsBy, TextChanges, LogicalBecomes, AnyValueChange.
⚠️ Common mistakes:EachTimeis an OccurrenceOption for AttributeTrigger's ScalarDetectStep — NOT valid in EventDetectStep. A bareAnyValueChangewithoutEventFieldSelectorbefore it causesRowCountMismatch. Another common mistake is overbuilding an Object/SplitEvent/Attribute graph for a rule that should just useSourceEvent+EventTrigger.
---
Row Kinds Quick Reference
State Conditions (fires while condition holds)
| kind | op values | Arguments |
|---|---|---|
NumberValueCondition | IsEqualTo, IsNotEqualTo, IsGreaterThan, IsGreaterThanOrEqualTo, IsLessThan, IsLessThanOrEqualTo | op (string), threshold (number) |
NumberRangeCondition | IsInsideRange, IsOutsideRange | op (string), low (number), includeLow (boolean), high (number), includeHigh (boolean) |
TextValueCondition | IsEqualTo, IsNotEqualTo, BeginsWith, Contains, EndsWith, DoesNotBeginWith, DoesNotContain, DoesNotEndWith | op (string), value (string) |
TextLengthCondition | HasLengthGreaterThan, HasLengthGreaterThanOrEqualTo, HasLengthLessThan, HasLengthLessThanOrEqualTo, HasLengthEqualTo, HasLengthNotEqualTo | op (string), length (number) |
LogicalValueCondition | IsEqual, IsNotEqual | op (string), value (boolean) |
Change Conditions (fires on transition)
| kind | op values | Arguments |
|---|---|---|
NumberBecomes | BecomesGreaterThan, BecomesGreaterThanOrEqualTo, BecomesLessThan, BecomesLessThanOrEqualTo | op (string), value (number) |
NumberEntersOrLeavesRange | EntersRange, LeavesRange | op (string), low (number), includeLow (boolean), high (number), includeHigh (boolean) |
NumberChanges | ChangesFrom, ChangesTo | op (string), value (number) |
NumberChangesFromTo | _(no op)_ | oldValue (number), newValue (number) |
NumberTrendsBy | DecreasesByAtLeast, IncreasesByAtLeast, ChangesByAtLeast | op (string), offset (number), inPercent (boolean) |
TextChanges | ChangesFrom, ChangesTo | op (string), value (string) |
TextChangesFromTo | _(no op)_ | oldValue (string), newValue (string) |
LogicalBecomes | BecomesTrue, BecomesFalse | op (string) |
AnyValueChange | Changes | op (string) |
Heartbeat Conditions
| kind | Arguments |
|---|---|
NoHeartbeat | duration (timeSpan) |
OnFirstHeartbeat | duration (timeSpan, optional) |
Occurrence Options (optional, follows a detection row in ScalarDetectStep)
| kind | Description | Arguments |
|---|---|---|
EachTime | Fire every time condition is met | _(none)_ |
ForNthTime | Fire after N occurrences within a window | n (number), duration (timeSpan) |
State Detector Option (optional, follows a state condition)
| kind | Description | Arguments |
|---|---|---|
SustainedPeriodOption | Condition must persist for a duration before firing | period (timeSpan) |
---
ScalarSelectStep — Attribute Selection & Aggregation
Attribute Reference
{ "name": "AttributeSelector", "kind": "Attribute",
"arguments": [{
"kind": "AttributeReference", "type": "complex", "name": "attribute",
"arguments": [{ "name": "entityId", "type": "string", "value": "<attribute-entity-guid>" }]
}] }Aggregation (NumberSummary)
{ "name": "NumberSummary", "kind": "NumberSummary",
"arguments": [
{ "name": "op", "type": "string", "value": "Average" },
{ "kind": "TimeDrivenWindowSpec", "type": "complex", "name": "window",
"arguments": [
{ "name": "width", "type": "timeSpan", "value": 600000.0 },
{ "name": "hop", "type": "timeSpan", "value": 600000.0 }
] }
] }Aggregation ops: Average, Sum, Min, Max, Count.
Time Windows (TimeDrivenWindowSpec)
Values in milliseconds: 1min=60000, 5min=300000, 10min=600000, 30min=1800000, 1hr=3600000, 6hr=21600000, 24hr=86400000.
width = window size. hop = advance interval (= width for tumbling, smaller for sliding).
---
ScalarDetectStep — Detection Conditions
Accepts one detection row (state or change — see Quick Reference), plus an optional occurrence modifier.
Default alerting preference: for most notification scenarios, prefer change / transition detectors over steady-state detectors. UseNumberBecomes,NumberEntersOrLeavesRange,LogicalBecomes, or other explicit change conditions even when the user uses state-like wording such as "is greater than", "is below", or "is outside the normal range". Interpret ordinary alert wording as "notify me when it crosses into that state". Reserve steady-state conditions likeIsGreaterThan,IsLessThan, andIsOutsideRangefor cases where repeated firing while the condition remains true is intentionally desired, such as "notify me every time it is greater than 30" or "fire on every evaluation while it is above 30".
NumberValueCondition
Note: Usesthreshold(notvalue) as argument name.
{ "name": "NumberValueCondition", "kind": "NumberValueCondition",
"arguments": [
{ "name": "op", "type": "string", "value": "IsGreaterThan" },
{ "name": "threshold", "type": "number", "value": 25.0 }] }NumberBecomes
Fires only on transition, not while condition remains true:
{ "name": "NumberBecomes", "kind": "NumberBecomes",
"arguments": [
{ "name": "op", "type": "string", "value": "BecomesGreaterThan" },
{ "name": "value", "type": "number", "value": 30.0 }] }Use BecomesGreaterThan / BecomesLessThan when the goal is to avoid alert spam from repeated evaluations of the same high / low state.
NumberEntersOrLeavesRange (change) & NumberRangeCondition (state)
⚠️ Range change uses `NumberEntersOrLeavesRange`, NOTNumberBecomes. Range state usesNumberRangeCondition.
Both share args: op, low (number), includeLow (boolean), high (number), includeHigh (boolean).
{ "name": "NumberEntersOrLeavesRange", "kind": "NumberEntersOrLeavesRange",
"arguments": [
{ "name": "op", "type": "string", "value": "LeavesRange" },
{ "name": "low", "type": "number", "value": 10.0 },
{ "name": "high", "type": "number", "value": 25.0 },
{ "name": "includeLow", "type": "boolean", "value": true },
{ "name": "includeHigh", "type": "boolean", "value": true }] }For state: use kind NumberRangeCondition with ops IsInsideRange / IsOutsideRange.
For most alerting scenarios, prefer EntersRange / LeavesRange over IsInsideRange / IsOutsideRange so the rule fires when the value crosses the boundary rather than on every subsequent evaluation while it remains in-range or out-of-range.
TextValueCondition
{ "name": "TextValueCondition", "kind": "TextValueCondition",
"arguments": [
{ "name": "op", "type": "string", "value": "IsEqualTo" },
{ "name": "value", "type": "string", "value": "Critical" }] }For prompts like "alert when more than 10 ERROR readings occur in 5 minutes", select the text/status attribute, use TextValueCondition with an op such as IsEqualTo, then add an OccurrenceOption row. Do not model this as NumberSummary / Count over the text attribute, and do not put count operators into TextValueCondition.op; the backend expects text conditions to receive text operators and will reject mismatched count/numeric encodings.
{ "name": "ScalarDetectStep", "id": "<guid>",
"rows": [
{ "name": "TextValueCondition", "kind": "TextValueCondition",
"arguments": [
{ "name": "op", "type": "string", "value": "IsEqualTo" },
{ "name": "value", "type": "string", "value": "ERROR" }] },
{ "name": "OccurrenceOption", "kind": "ForNthTime",
"arguments": [
{ "name": "n", "type": "number", "value": 11 },
{ "name": "duration", "type": "timeSpan", "value": 300000 }] }
] }Use n = threshold + 1 for "more than N" wording. For example, "more than 10 ERROR readings" maps to ForNthTime with n = 11 in the 5-minute window.
TextLengthCondition
{ "name": "TextLengthCondition", "kind": "TextLengthCondition",
"arguments": [
{ "name": "op", "type": "string", "value": "HasLengthGreaterThan" },
{ "name": "length", "type": "number", "value": 100 }] }LogicalBecomes (change) & LogicalValueCondition (state)
Attribute must use "Logical" TypeAssertion.
{ "name": "LogicalBecomes", "kind": "LogicalBecomes",
"arguments": [{ "name": "op", "type": "string", "value": "BecomesTrue" }] }{ "name": "LogicalValueCondition", "kind": "LogicalValueCondition",
"arguments": [
{ "name": "op", "type": "string", "value": "IsEqual" },
{ "name": "value", "type": "boolean", "value": false }] }NumberTrendsBy
⚠️ Row name ≠ kind:nameis"NumberTrends",kindis"NumberTrendsBy". Wrong name causes API rejection.
{ "name": "NumberTrends", "kind": "NumberTrendsBy",
"arguments": [
{ "name": "op", "type": "string", "value": "IncreasesByAtLeast" },
{ "name": "offset", "type": "number", "value": 10.0 },
{ "name": "inPercent", "type": "boolean", "value": false }] }Set inPercent: true for percentage-based trends.
Value Change Detection
⚠️ Row name ≠ kind for `FromTo` variants:NumberChangesFromToandTextChangesFromTokinds use row names"NumberChanges"and"TextChanges"respectively.
{ "name": "NumberChanges", "kind": "NumberChanges",
"arguments": [
{ "name": "op", "type": "string", "value": "ChangesTo" },
{ "name": "value", "type": "number", "value": 0 }] }{ "name": "TextChanges", "kind": "TextChanges",
"arguments": [
{ "name": "op", "type": "string", "value": "ChangesTo" },
{ "name": "value", "type": "string", "value": "ERROR" }] }{ "name": "AnyValueChange", "kind": "AnyValueChange",
"arguments": [{ "name": "op", "type": "string", "value": "Changes" }] }Name ≠ Kind Reference
Row Name (name) | Picker Kind (kind) |
|---|---|
NumberTrends | NumberTrendsBy |
NumberChanges | NumberChanges or NumberChangesFromTo |
TextChanges | TextChanges or TextChangesFromTo |
Heartbeat Conditions (AttributeTrigger ScalarDetectStep only)
{ "name": "OnFirstHeartbeat", "kind": "OnFirstHeartbeat", "arguments": [] }{ "name": "NoHeartbeat", "kind": "NoHeartbeat",
"arguments": [{ "name": "duration", "type": "timeSpan", "value": 300000 }] }---
Occurrence Options
{ "name": "OccurrenceOption", "kind": "EachTime", "arguments": [] }{ "name": "OccurrenceOption", "kind": "ForNthTime",
"arguments": [
{ "name": "n", "type": "number", "value": 5 },
{ "name": "duration", "type": "timeSpan", "value": 3600000 }] }SustainedPeriodOption — state detector option, placed after a state condition row:
{ "name": "SustainedPeriodOption", "kind": "SustainedPeriodOption",
"arguments": [{ "name": "period", "type": "timeSpan", "value": 300000 }] }---
DimensionalFilterStep — Additional Filters
Optional step filtering which objects the rule applies to. Uses same condition kinds as ScalarDetectStep.
{ "name": "DimensionalFilterStep", "id": "<guid>",
"rows": [
{ "name": "AttributeSelector", "kind": "Attribute",
"arguments": [{
"kind": "AttributeReference", "type": "complex", "name": "attribute",
"arguments": [{ "name": "entityId", "type": "string", "value": "<filter-attribute-guid>" }]
}] },
{ "name": "TextValueCondition", "kind": "TextValueCondition",
"arguments": [
{ "name": "op", "type": "string", "value": "IsEqualTo" },
{ "name": "value", "type": "string", "value": "Medicine" }] }
] }---
Enrichments — Adding Context to Notifications
Enrichments are references to existing BasicEventAttribute entities placed in the rule's ActStep action binding. Create the attribute entity first, then reference it from the action payload.
⚠️ AttributeTrigger + TeamsMessage guidance
>
Dynamic Teams content can appear inline in the message/body, but the inlineAttributeReferenceshape is different from the structuredadditionalInformationshape:
>
- Inline mixed-content parts inheadline/optionalMessageuse{"kind":"AttributeReference","type":"complex","arguments":[...]}directly inside the field'svaluesarray.
- Structured entries inadditionalInformationuseNameReferencePairwhosereferenceargument is{"kind":"AttributeReference","type":"complexReference","name":"reference",...}.
>
When adding dynamic Teams content to anAttributeTrigger, follow the exact shapes below rather than converting everything tocomplexReference.
Inline mixed content in optionalMessage
Working readback shape for inline dynamic text in an AttributeTrigger Teams action:
{
"name": "optionalMessage",
"type": "array",
"values": [
{ "name": "string", "type": "string", "value": "The humidity of this package has crossed above or below the allowed range." },
{
"kind": "AttributeReference",
"type": "complex",
"arguments": [{ "name": "entityId", "type": "string", "value": "<humidity-attr-id>" }]
},
{ "name": "string", "type": "string", "value": " " }
]
}Use the same mixed-content values array pattern if you need inline dynamic parts in headline.
Recommended AttributeTrigger Teams pattern
Combine inline message content and structured additionalInformation like this:
{
"name": "TeamsBinding",
"kind": "TeamsMessage",
"arguments": [
{ "name": "messageLocale", "type": "string", "value": "" },
{ "name": "recipients", "type": "array", "values": [
{ "type": "string", "value": "user@example.com" }
]},
{ "name": "headline", "type": "array", "values": [
{ "type": "string", "value": "Building-B critical temperature alert" }
]},
{ "name": "optionalMessage", "type": "array", "values": [
{ "name": "string", "type": "string", "value": "The current temperature is " },
{
"kind": "AttributeReference",
"type": "complex",
"arguments": [{ "name": "entityId", "type": "string", "value": "<temp-attr-id>" }]
},
{ "name": "string", "type": "string", "value": " and pressure context is included below." }
]},
{ "name": "additionalInformation", "type": "array", "values": [
{
"kind": "NameReferencePair",
"type": "complex",
"arguments": [
{ "name": "name", "type": "string", "value": "Current Temperature" },
{
"kind": "AttributeReference",
"type": "complexReference",
"name": "reference",
"arguments": [{ "name": "entityId", "type": "string", "value": "<temp-attr-id>" }]
}
]
},
{
"kind": "NameReferencePair",
"type": "complex",
"arguments": [
{ "name": "name", "type": "string", "value": "Current Pressure" },
{
"kind": "AttributeReference",
"type": "complexReference",
"name": "reference",
"arguments": [{ "name": "entityId", "type": "string", "value": "<pressure-attr-id>" }]
}
]
}
]}
]
}Structured References in additionalInformation
By attribute entity ID (`AttributeReference`):
{ "name": "additionalInformation", "type": "array",
"values": [{
"kind": "NameReferencePair", "type": "complex",
"arguments": [
{ "name": "name", "type": "string", "value": "Current Temperature" },
{ "kind": "AttributeReference", "type": "complexReference", "name": "reference",
"arguments": [{ "name": "entityId", "type": "string", "value": "<attr-id>" }] }
] }] }By raw event field name (`EventFieldReference`):
{ "kind": "NameReferencePair", "type": "complex",
"arguments": [
{ "name": "name", "type": "string", "value": "Device ID" },
{ "kind": "EventFieldReference", "type": "complexReference", "name": "reference",
"arguments": [{ "name": "fieldName", "type": "string", "value": "deviceId" }] }
] }UseEventFieldReferenceonly when the rule template resolves raw event fields directly (commonlyEventTrigger). ForAttributeTrigger, preferAttributeReferenceto the existing attribute entity.
Which Action Fields Accept Enrichments
| Field | Accepts |
|---|---|
headline | Array of content parts; use strings or mixed string + inline AttributeReference parts (type: "complex") |
optionalMessage | Array of content parts; use strings or mixed string + inline AttributeReference parts (type: "complex") |
subject (EmailMessage only) | Static text + AttributeReference |
additionalInformation | NameReferencePair with AttributeReference; EventFieldReference only when the rule template exposes raw event fields |
Activator Entity Types — High-Level Entity Map
---
This reference is the high-level map of the main public entity types you assemble in ReflexEntities.json.
It covers:
- the shared entity envelope used by all entities
- the top-level
container-v1grouping entity - the supported source entity types
- the main
timeSeriesView-v1variants used to model events, objects, attributes, and rules
Standalone action entities such as fabricItemAction-v1 are part of the overall Activator entity model too, but they are documented separately in action-types.md.
High-level entity type map
| Category | Entity type(s) | Purpose |
|---|---|---|
| Shared envelope | all entities | Common uniqueIdentifier + payload + type wrapper |
| Container | container-v1 | Top-level grouping entity for hand-authored graphs |
| Sources | eventstreamSource-v1, kqlSource-v1, digitalTwinBuilderSource-v1, realTimeHubSource-v1 | Connect Activator to upstream data |
| Views | timeSeriesView-v1 | Model events, objects, attributes, and rules via payload.definition.type |
| Actions | fabricItemAction-v1 | Standalone invokable Fabric item actions used by rules |
Shared entity envelope
Every entity in ReflexEntities.json:
{ "uniqueIdentifier": "<GUID>", "payload": { }, "type": "<entity-type-string>" }| Field | Type | Required | Description |
|---|---|---|---|
uniqueIdentifier | GUID | yes | Unique ID — other entities reference this |
payload | object | yes | Entity-specific configuration |
type | string | yes | Entity type (see below) |
---
Container (container-v1)
Top-level grouping entity used by the hand-authored pull-source flows in this skill. KQL, DTB, and Real-time Hub examples should keep using explicit container references. Eventstream sink-created entities are different: in public readback they can appear without an explicit parentContainer.
{
"uniqueIdentifier": "<container-guid>",
"payload": {
"name": "Package delivery sample",
"type": "samples"
},
"type": "container-v1"
}| Property | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name |
type | string | yes | Classification (e.g. samples, kqlQueries, rthSubscriptions) |
---
Source entity types
| Source | Entity Type | Reference | Use Case |
|---|---|---|---|
| Eventstream | eventstreamSource-v1 | eventstream-source.md | Push source created by configuring Activator as an Eventstream destination |
| KQL / Eventhouse | kqlSource-v1 | kql-source.md | Scheduled queries against a KQL database |
| Digital Twin Builder / Ontology | digitalTwinBuilderSource-v1 | dtb-source.md | Scheduled DTB / ontology queries against an existing Fabric item |
| Real-time Hub | realTimeHubSource-v1 | real-time-hub-source.md | Fabric workspace event monitoring |
---
View Types (timeSeriesView-v1)
Views are not sources themselves, but they sit between sources and rules. They are all entity type timeSeriesView-v1, distinguished by payload.definition.type.
Event View (SourceEvent)
Connects to a source and defines what events to process.
Event-trigger shortcut: For pureEventTriggerrules,SourceEventis usually the last view you need before the rule. You do not need Object, SplitEvent, IdentityPartAttribute, or BasicEventAttribute entities just to fire on raw events.
>
Eventstream note: An Eventstream Activator sink can auto-create aSourceEventview with no explicitparentContainerand withtemplateVersion: "1.1". When extending an Eventstream-backed Activator, preserve the shape already present in the decoded definition instead of forcing the generic container-based example below.
{
"uniqueIdentifier": "<source-event-guid>",
"payload": {
"name": "Sensor events",
"parentContainer": { "targetUniqueIdentifier": "<container-guid>" },
"definition": {
"type": "Event",
"instance": "<JSON-encoded SourceEvent template>"
}
},
"type": "timeSeriesView-v1"
}SourceEvent template:
{
"templateId": "SourceEvent",
"templateVersion": "1.2.4",
"steps": [{
"name": "SourceEventStep",
"id": "<guid>",
"rows": [{
"name": "SourceSelector",
"kind": "SourceReference",
"arguments": [{"name": "entityId", "type": "string", "value": "<source-entity-guid>"}]
}]
}]
}SplitEvent View
SplitEvent is optional — it splits events by object identity when needed. BasicEventAttribute can reference SourceEvent directly. Sits between SourceEvent and Attributes. Maps events to objects using an identity field.
Do not use SplitEvent for pure event triggers. SplitEvent is only for object/attribute modeling when you need to turn raw events into per-object attributes for AttributeTrigger rules.{
"uniqueIdentifier": "<split-event-guid>",
"payload": {
"name": "SplitEvent",
"parentObject": { "targetUniqueIdentifier": "<object-guid>" },
"parentContainer": { "targetUniqueIdentifier": "<container-guid>" },
"definition": {
"type": "Event",
"instance": "<JSON-encoded SplitEvent template>"
}
},
"type": "timeSeriesView-v1"
}SplitEvent template:
When SplitEvent is included, SplitEventStep MUST have EventSelector + SplitEventOptions (both required), plus zero or more FieldIdMapping rows.
{
"templateId": "SplitEvent",
"templateVersion": "1.2.4",
"steps": [{
"name": "SplitEventStep",
"id": "<guid>",
"rows": [
{
"name": "EventSelector",
"kind": "Event",
"arguments": [{
"kind": "EventReference",
"type": "complex",
"arguments": [{"name": "entityId", "type": "string", "value": "<source-event-entity-guid>"}],
"name": "event"
}]
},
{
"name": "FieldIdMapping",
"kind": "FieldIdMapping",
"arguments": [
{"name": "fieldName", "type": "string", "value": "<identity-field-name>"},
{
"kind": "AttributeReference",
"type": "complex",
"arguments": [{"name": "entityId", "type": "string", "value": "<identity-attribute-entity-guid>"}],
"name": "idPart"
}
]
},
{
"name": "SplitEventOptions",
"kind": "EventOptions",
"arguments": [{"name": "isAuthoritative", "type": "boolean", "value": true}]
}
]
}]
}Note: BasicEventAttribute entities can reference either the SplitEvent or SourceEvent entity in their EventReference entityId. When SplitEvent is not used, reference SourceEvent directly.Object View
Groups events by an identity (e.g., a specific package, device, or customer).
{
"uniqueIdentifier": "<object-guid>",
"payload": {
"name": "Package",
"parentContainer": { "targetUniqueIdentifier": "<container-guid>" },
"definition": { "type": "Object" }
},
"type": "timeSeriesView-v1"
}Attribute View
Extracts a specific field from events. Attributes belong to an Object via parentObject.
{
"uniqueIdentifier": "<attribute-guid>",
"payload": {
"name": "Temperature (°C)",
"parentObject": { "targetUniqueIdentifier": "<object-guid>" },
"parentContainer": { "targetUniqueIdentifier": "<container-guid>" },
"definition": {
"type": "Attribute",
"instance": "<JSON-encoded BasicEventAttribute template>"
}
},
"type": "timeSeriesView-v1"
}IdentityPartAttribute Template
Defines an identity field for object grouping (e.g., SensorId, DeviceId). Uses a single IdPartStep with a TypeAssertion row.
{
"templateId": "IdentityPartAttribute",
"templateVersion": "1.2.4",
"steps": [{
"name": "IdPartStep",
"id": "<guid>",
"rows": [{
"name": "TypeAssertion",
"kind": "TypeAssertion",
"arguments": [
{ "name": "op", "type": "string", "value": "Text" },
{ "name": "format", "type": "string", "value": "" }
]
}]
}]
}BasicEventAttribute Template
Extracts a field value from events. Has TWO steps: EventSelectStep (selects the event and field) and EventComputeStep (asserts the data type).
{
"templateId": "BasicEventAttribute",
"templateVersion": "1.2.4",
"steps": [
{
"name": "EventSelectStep",
"id": "<guid>",
"rows": [
{
"name": "EventSelector",
"kind": "Event",
"arguments": [{
"kind": "EventReference",
"type": "complex",
"arguments": [{ "name": "entityId", "type": "string", "value": "<source-event-entity-guid>" }],
"name": "event"
}]
},
{
"name": "EventFieldSelector",
"kind": "EventField",
"arguments": [{ "name": "fieldName", "type": "string", "value": "<field-name>" }]
}
]
},
{
"name": "EventComputeStep",
"id": "<guid>",
"rows": [{
"name": "TypeAssertion",
"kind": "TypeAssertion",
"arguments": [
{ "name": "op", "type": "string", "value": "Number" },
{ "name": "format", "type": "string", "value": "" }
]
}]
}
]
}TypeAssertion `op` values: Use"Number"for numeric fields,"Text"for text/string fields.
EventReference `entityId`: Points to the SourceEvent entity (or SplitEvent if used).
Related skills
FAQ
What does activator-authoring-cli produce?
Fabric Activator reflex items with ReflexEntities rules, data sources, conditions, and Teams, email, or item invocation actions.
When should I use activator-authoring-cli?
When creating or updating Fabric Activator alerts and notification flows via CLI and REST API.
Is activator-authoring-cli safe to install?
Review the Security Audits panel on this page before installing in production.