Smartsheet Row Change to CRM/ERP Sync
When a key row changes on a Smartsheet sheet (status, amount, dates), the flow updates the matching record in Dataverse or a CRM/ERP, creates follow-up activities, and writes the system reference back to the row. Keeps Smartsheet operational tracking aligned with the system of record.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
This flow keeps Smartsheet aligned with the business system of record. On a 15-minute schedule it reads every row from an operational Smartsheet sheet, upserts each row into a Dataverse mirror table (flowlibs_crmordermirror), writes the resulting Dataverse record id back onto the Smartsheet row, and posts a notification to Microsoft Teams. New rows create a record; existing rows are updated in place (idempotent upsert keyed on the stable Smartsheet row id).
Why it matters: Teams track operationally in Smartsheet, but the business system holds the truth. Syncing changed rows avoids divergence and double entry, and the write-back of the record id gives each Smartsheet row a durable link to its system-of-record counterpart.
Use Case
A sales/operations team manages working items (orders, deals, projects) in a Smartsheet sheet with columns such as Item, Status, Amount, Due Date, and Contact Email. The business records of truth live in Dataverse (or a CRM/ERP fronted by Dataverse). This flow continuously reflects material Smartsheet changes into Dataverse, stamps each Dataverse record id back onto the originating Smartsheet row, and keeps the operations channel informed of every create/update.
Flow Architecture
Recurrence
Recurrence (built-in)Poll every 15 minutes. The Smartsheet connector has no row-level change trigger, so a recurrence poll is the connector-first pattern.
Initialize Correlation Id
Initialize VariableMint a guid() correlation id stamped on every synced record and notification.
Initialize Sheet Id / Column titles / Api Token
Initialize VariableBind the sheet id, configurable Smartsheet column titles, and the REST API token to variables.
Initialize Ref Column Id
Initialize VariableNumeric Smartsheet columnId of the write-back column.
Initialize Teams Group Id / Channel Id
Initialize VariableTarget Teams team + channel for notifications.
Get Smartsheet Rows
Smartsheet — GetSheetDataRead all rows from the sheet (dynamic schema keyed by column titles).
Apply to each
ForeachProcess each row.
List Existing Record
Microsoft Dataverse — ListRecordsDedup lookup on flowlibs_smartsheetrowid eq '<row id>'.
Condition Is New Row
Condition (If)@empty(outputs('List_Existing_Record')?['body/value']).
Create Mirror Record (Yes)
Microsoft Dataverse — CreateRecordCreate the system-of-record mirror record.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_SmartsheetSheetId | String | REPLACE_WITH_SMARTSHEET_SHEET_ID | Sheet id to poll. |
| flowlibs_SmartsheetApiToken | String | <configure> | Bearer token for the REST write-back. |
| flowlibs_SmartsheetStatusColumn | String | Status | Title of the Status column. |
| flowlibs_SmartsheetEmailColumn | String | Contact Email | Title of the owner/contact email column. |
| flowlibs_TeamsGroupId | String | <your-team-id> | Target Teams team. |
| flowlibs_TeamsChannelId | String | <your-channel-id> | Target Teams channel. |
| flowlibs_SmartsheetRefColumnId | String | REPLACE_WITH_RECORD_ID_COLUMN_ID | Numeric columnId of the write-back column. |
| flowlibs_SmartsheetRowNameColumn | String | Item | Title of the row/item name column. |
| flowlibs_SmartsheetAmountColumn | String | Amount | Title of the Amount column. |
| flowlibs_SmartsheetDueDateColumn |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Smartsheet | shared_smartsheet | GetSheetData |
| HTTP | http | PUT /2.0/sheets/{id}/rows |
| Microsoft Dataverse | shared_commondataserviceforapps | ListRecords CreateRecord UpdateRecord |
| Microsoft Teams | shared_teams | PostMessageToConversation |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- CRM/ERP target
- Swap the Dataverse mirror table for Salesforce/Dynamics by replacing the three Dataverse actions with the equivalent connector ops; keep the same upsert/write-back shape.
- Field filter
- Only sync material fields, or add a Condition before upsert to skip rows whose Status hasn't changed (compare incoming Status to the stored mirror record).
- Event-driven
- Replace the Recurrence trigger with the Smartsheet OnUpdatedSpecificSheet / OnRowCreated trigger for near-real-time sync.
- Conflict log
- Record mismatches (e.g. Smartsheet vs. Dataverse value drift) to an audit table.
- Column titles
- All read column titles are env vars, so the flow ports to any sheet by changing values only.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Dedup filter
Dedupe lookup on the stable Smartsheet row id.
EXPR.02Is new row
True when no mirror record exists yet.
EXPR.03Dynamic column read (env-var-driven title)
Reads a cell by configurable column title.
EXPR.04Existing record id (for update / write-back)
Pulls the existing mirror record id.
EXPR.05REST write-back body
Writes the Dataverse record id back to the row.
Customize & download
Generate a ready-to-import copy of this solution with your environment-variable values baked in — available on Base, Pro, or Team.
Upgrade to customize
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.