Asking for Reviews on Microsoft 365
The same standard, for a trade business that lives in Microsoft 365: Power Automate reads the job system for finished jobs, every customer gets the same message and review link, and a low score texts the owner.
Used by
- AI Officer
- Business Systems Analyst
- Office Manager
How to get this live in your business
The message is the easy part. What takes thought is the same as on any stack: the flow reads the job system at the moment of sending, so a job with an open callback waits; every customer gets the words from one row in Rules, so there is nowhere for a second link to live; and an opt-out is kept against the customer, where no later job can reach it.
In short
What this is
A build plan for the Review Request standard on Microsoft 365. Five lists, three flows, and a job system Power Automate can read.
The core rule
Flow 1 builds every ask from Rules.MessageText and Rules.ReviewLink with only the name filled in. No list has a column for a different link or a score threshold.
What it does not do
No flow sends anything to a customer after they reply, and no flow posts or answers a review. A low score adds an alert to the owner in Teams or by SMS.
The hard part
Reading callbacks, disputes and complaints from the job system each time a message would go, and matching a reply that arrives days later back to its job.
Take the spec to Claude, ChatGPT or Copilot. The sentence to paste is one click away.
Want the whole thing by email?
This paper, plus the rest of the library. One click to stop them.
1. Before you start
Read the Review Request build standard first. It defines its objects, and the lists below are those objects with SharePoint types on them. Shared conventions are in building the standards on Microsoft 365.
Check what your job system lets a flow read. ServiceM8, Simpro, Fergus, Jobber and AroFlo each have an integration route, usually through an HTTP action with a key the business owns rather than a ready connector. You need job status and its timestamps, linked callback jobs, and the invoice’s disputed state. Tradify has no public API, so this plan cannot read it live.
Then decide where the texts go from. An SMS provider with a connector or an HTTP API, on an account the business owns, with inbound replies forwarded back into Flow 2. Email works the same way through a shared Outlook mailbox. Fill in the one Rules row before switching anything on.
2. The lists, with their columns
For your developer. Show the fields for your developer
Site: ReviewRequests
LIST Rules (one row, written by the owner)
Trigger Choice indexed, REQUIRED. complete | paid
WaitHours Number REQUIRED. after the trigger, before the ask
ReminderHours Number REQUIRED. after the ask, before the one reminder
WindowDays Number REQUIRED. at most one ask per customer in this many days
ReviewLink Hyperlink REQUIRED. the only link any message carries
MessageText Note REQUIRED. the one ask, with {name} and the link
ReminderText Note REQUIRED
LIST Asks (one per job. Never two.)
JobId Text indexed, UNIQUE, REQUIRED
CustomerId Text indexed, REQUIRED
TriggeredAt DateTime read from the job system
Channel Choice sms | email
the customer's channel on record
AskedAt DateTime
RemindedAt DateTime set once; no flow sets it twice
Status Choice waiting | held | asked | reminded | replied
| review_marked | skipped_window | opted_out
ReviewMarkedBy Person the office marked the review as posted
LIST Holds (read from the job, never a score)
Ask Text lookup to Asks
Reason Choice REQUIRED. open_callback | invoice_disputed
| open_complaint
RaisedAt DateTime indexed
ClearedAt DateTime when the job system shows it closed
LIST OptOuts (no flow clears a row)
CustomerId Text indexed, UNIQUE
Said Note their words, exactly
ReceivedAt DateTime
LIST Replies (append only)
Ask Text lookup to Asks
ReplyText Note REQUIRED. exactly as received
Score Number 1 to 5 if they gave one; blank otherwise
ReceivedAt DateTime indexed
OwnerAlertedAt DateTime set for a 1, 2 or 3
OwnerCalledAt DateTime typed by the owner
There is no link column on Asks, no score threshold anywhere, and no feedback-form address. Every message is built from Rules.MessageText or Rules.ReminderText and Rules.ReviewLink, so every customer gets the same words and the same link.
An OptOuts row has no ClearedAt. If the customer themselves asks to hear from you again, a person removes the row and records why.Unique values on Asks.JobId is the line that holds one ask per job: a second run fails at SharePoint rather than sending twice. Unique CustomerId on OptOuts keeps one opt-out per customer, whichever job it came from.
3. Every rule, and what enforces it
| The rule | Enforced by | How |
|---|---|---|
| The ask starts when the job system says the job is finished | Flow 1, Rules.Trigger | Flow 1 polls the job system and only creates an Asks row for a job whose status matches Rules.Trigger, with TriggeredAt taken from the job system's own timestamp. |
| The ask waits the written time | Flow 1, Rules.WaitHours | A row stays waiting until TriggeredAt plus WaitHours has passed. The number lives in Rules, not in the flow. |
| Every customer gets the same message and the same link | Rules.MessageText and Rules.ReviewLink | The send action composes from those two columns and the customer's name. There is no other text source and no other link anywhere in the site. |
| A job that is not finished is held, and read again at sending | Flow 1, the Holds list | Just before the send, Flow 1 re-reads the job. An open callback, disputed invoice or open complaint writes a Holds row, posts the reason to the owner, and skips the send. |
| One ask per customer per window | Flow 1, Asks.CustomerId, Rules.WindowDays | Flow 1 filters Asks on CustomerId for an AskedAt inside the window and marks the job skipped_window instead of sending. |
| A STOP is for good, and a low score alerts the owner | Flow 2, OptOuts and Replies | Flow 2 appends the reply exactly, writes OptOuts on STOP, and on a score of 1 to 3 alerts the owner. It has no action that sends to the customer. |
4. The three flows
For your developer. Show the fields for your developer
FLOW 1 Finished job to ask
trigger every 15 minutes
logic read jobs from the job system whose status matches
Rules.Trigger; create Asks row (JobId unique), waiting
waiting and TriggeredAt + WaitHours passed:
re-read the job from the job system
open callback / disputed invoice / open complaint
-> Holds row with Reason, post to the owner, skip
CustomerId in OptOuts -> opted_out, skip
another ask to CustomerId inside WindowDays
-> skipped_window
no mobile and no email -> post to the owner, skip
send Rules.MessageText with the name and ReviewLink
-> AskedAt, Status asked
held and the job system shows it clear -> ClearedAt,
back to waiting, so the same ask goes the same way
never choose the text or the link by anything about the customer.
FLOW 2 A reply arrives
trigger an inbound SMS webhook, or a new email in the shared box
logic match the sender to the newest Asks row for that customer
append to Replies with the text exactly as received
STOP or unsubscribe -> OptOuts row
a score of 1, 2 or 3 -> alert the owner with the job,
the customer and the reply; set OwnerAlertedAt
set the Asks row to replied
never send anything to the customer.
FLOW 3 The one reminder
trigger daily, 10am
logic Asks rows with Status asked, RemindedAt blank,
AskedAt + ReminderHours passed, no Replies row and
no ReviewMarkedBy, CustomerId not in OptOuts
send Rules.ReminderText with the name and ReviewLink
-> RemindedAt, Status reminded
never remind a row whose RemindedAt is already set.Flow 2 is the only flow that reads replies, and it has no send action. An owner who wants to answer a customer answers them as themselves, by phone.
5. The order to build it in
- Create the five lists from the schema, with Asks.JobId and OptOuts.CustomerId unique, and fill in the one Rules row.
- Build Flow 1 up to the hold, and prove a job with an open callback gets a Holds row and no send.
- Add the send, and prove two customers get the same words with the same link.
- Build Flow 2 against your own phone, and prove a 2 alerts the owner and a STOP writes OptOuts.
- Build Flow 3, and prove a customer who replied gets no reminder.
6. Four traps specific to this build
Switching on the review tool's own score-first feature
Some SMS and review add-ons offer to send the link only to a 4 or a 5. That is review gating. Leave it off, and keep the link in Rules where every message reads it.
Deciding the hold when the job is first seen
A callback raised during the wait must still hold the ask. Re-read the job in the same run as the send, not in an earlier one.
Keeping the opt-out on the Asks row
Next month's job is a new Asks row. If the STOP lived on last month's row, Flow 1 would ask them again.
Asking Copilot to draft a reply to the review
Answering reviews is the owner's. No flow here posts to Google or replies on it, and none should.
7. Where the automation stops
- Answering every Google review, and the call to every low score.
- Closing callbacks, settling disputes and closing complaints in the job system.
- Writing the message, the wait, the reminder interval and the window.
- Marking a review as posted, and taking anyone off OptOuts, which happens only if they ask.
The pass test. Mark two real jobs complete in your job system, one with a callback job open against it, with your own mobile as the customer on both. After the wait, the clean job gets one ask and the other has a Holds row naming the open callback. Reply 2 from your phone: the owner is alerted, Replies holds your words exactly, and nothing more arrives on your phone. Close the callback: the second job gets the same message, word for word. A minute to stage on your own tenant, then the wait.