Bookings Post-Visit Survey and Review Request
After a Microsoft Bookings appointment completes, the flow sends the customer a SurveyMonkey satisfaction survey; happy respondents get a public-review request (Google/Trustpilot link) and detractors get a private service-recovery follow-up. Responses are logged to Dataverse. Turns each visit into feedback and reputation.
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 solution turns every Microsoft Bookings visit into feedback and reputation. Shortly after an appointment completes, the customer is emailed a SurveyMonkey satisfaction survey. When they respond, promoters (high scores) get a public-review request while detractors (low scores) get a private internal service-recovery follow-up - and every response is logged to Dataverse for reporting.
Why it matters: Satisfied customers will leave reviews if asked at the right moment; unhappy ones need quiet recovery, not a public prompt. Routing by score maximizes reputation while protecting it.
Built as two flows + one Dataverse table in a single solution. SurveyMonkey is a per-flow trigger on the response side, so the "send" and "route" halves are separate flows that share the survey id and the log table.
Architecture decisions: Bookings is trigger-only - the connector has no read/"appointment completed" action, so Flow A reads completed appointments on a schedule via Microsoft Graph calendarView (app-only OAuth). SurveyMonkey has no per-recipient send - the connector's SendMessage only re-sends a collector's pre-built blast, so Flow A sends the personalized survey invite via Outlook (SendEmailV2) using the survey link, and still showcases the SurveyMonkey connector via GetSurvey (live title + collect URL). Flow B uses the real SurveyMonkey response trigger. Flows ship Off (demo).
Use Case
A services business (clinic, salon, studio, repair shop) wants automatic post-visit surveys with smart routing: thank-and-amplify happy customers, quietly recover unhappy ones, and keep a governed record of all feedback.
Flow Architecture
Every_Hour_Check_For_Completed_Visits (Flow A)
Recurrence (1 hr)Polls hourly for newly completed visits.
Get_Completed_Appointments (Flow A)
HTTP (Graph, ActiveDirectoryOAuth)GET /v1.0/solutions/bookingBusinesses/{id}/calendarView?start=&end=.
Get_Survey (Flow A)
SurveyMonkey GetSurveyLive survey title + collect URL for personalization.
For_Each_Appointment (Flow A)
ForeachPer appointment with an email: send the survey invite (Outlook) and log a Survey Sent row (Dataverse).
When_A_Survey_Response_Is_Submitted (Flow B)
SurveyMonkey OnNewResponseAddedSurvey (poll 5 min, splitOn)Fires per new survey response.
Compose_Score / Compose_Sentiment (Flow B)
ComposeDerives the numeric score and Promoter/Detractor sentiment vs the threshold.
Route_By_Sentiment (Flow B)
Condition (If-else)Promoter -> review request (Outlook); Detractor -> private recovery follow-up (Outlook).
Log_Survey_Response (Flow B)
Dataverse CreateRecordLogs the response with score and sentiment.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_SurveyId | String | SURVEY_ID_PLACEHOLDER | SurveyMonkey survey id. Used by Flows A + B. |
| flowlibs_SurveyLink | String | https://www.surveymonkey.com/r/PLACEHOLDER | Public survey URL emailed to the customer (Flow A). |
| flowlibs_ReviewLink | String | https://g.page/r/PLACEHOLDER/review | Public review link sent to promoters (Flow B). |
| flowlibs_PromoterThreshold | String | 9 | Minimum score to be treated as a promoter (Flow B). |
| flowlibs_RecoveryAlertEmail | String | service-recovery@yourcompany.com | Internal mailbox alerted for detractor recovery (Flow B). |
| flowlibs_BookingsBusinessId | String | <configure> | Bookings business id for the Graph calendarView read (Flow A). |
| flowlibs_GraphBaseUrl | String | https://graph.microsoft.com | Graph base URL (Flow A). |
| flowlibs_GraphTenantId | String | <your-tenant-id> | Tenant id for app-only Graph OAuth (Flow A). |
| flowlibs_GraphClientId | String | <configure> | App registration client id (Flow A). |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| SurveyMonkey | shared_surveymonkey | GetSurvey OnNewResponseAddedSurvey |
| Office 365 Outlook | shared_office365 | SendEmailV2 |
| Microsoft Dataverse | shared_commondataserviceforapps | CreateRecord |
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.
- Score mapping
- At go-live, point Compose_Score (Flow B) at your rating question's answer instead of the response custom value.
- Wait before surveying
- Increase the recurrence interval / lookback, or add a delay, so customers aren't surveyed the instant they leave.
- SMS survey
- Add Twilio to send the invite by SMS for higher response rates.
- Staff attribution
- Capture the appointment's staffMemberIds and store it on the log row to tie feedback to a staff member.
- Incentive
- Offer a discount code in the invite email for completing the survey.
- Threshold tuning
- Adjust flowlibs_PromoterThreshold to change the promoter/detractor cutoff without editing flow logic.
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.01Scan window start
Lower bound of the completed-visit scan window.
EXPR.02Graph calendarView URI
Reads completed appointments in the window.
EXPR.03Customer email (Bookings)
Resolves the customer email defensively.
EXPR.04Sentiment
Classifies the respondent by score.
EXPR.05Promoter gate (If)
Routes promoters to the review-request branch.
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.