Testimonial generation & verification flow
An end-to-end guide to the automated testimonial pipeline: a student submits a request in Power Apps, it lands in SharePoint, Power Automate routes it for approval, generates a signed PDF from a Word template, and the result is cross-checked against PAIR.gov.sg before release.
Overview & architecture
The whole pipeline in one picture — read this first, then use the sidebar to jump to any step for the detailed build instructions.
This document assumes your Digitisation team already has: an Office 365 tenant with Power Apps & Power Automate licensing, a SharePoint site for the school/division, and admin access to create lists, connections and flows. See Licensing & permissions for exact requirements.
Power Apps — Testimonial Request form
A canvas app that writes directly into the SharePoint list. Keep it to one screen — students shouldn't need training to use it.
Recommended fields
| Field (control) | Type | Maps to SharePoint column |
|---|---|---|
| Student Name | Text input | StudentName |
| Student ID | Text input (validated) | StudentID |
| Programme / Course | Dropdown | Programme |
| Purpose of testimonial | Dropdown (Internship, Scholarship, Further studies, Other) | Purpose |
| Additional remarks | Multiline text | Remarks |
| Student email | Text input (auto-fill from User().Email) | StudentEmail |
Build the Submit button with SubmitForm(TestimonialForm) or
Patch('Testimonial Requests', Defaults('Testimonial Requests'), {...}) if you're using controls
directly instead of a Form control. Add a confirmation screen so the student sees a reference number.
Since this is a school-facing form, prefer signing students in with their O365 account (User().Email)
rather than a free-text email field — it prevents impersonation and auto-fills identity.
Student submission
What happens the moment the student taps Submit.
- The app validates required fields client-side (Power Apps
DisplayMode/Requiredchecks) before allowing submission. - On submit, a new row is written to the SharePoint list with
Status = "Pending". - The app shows a confirmation screen with the new item's
ID, which doubles as a tracking reference.
SharePoint list — the data store
This list is the single source of truth the whole flow reads from and writes back to.
List: Testimonial Requests
| Column | Type | Purpose |
|---|---|---|
| Title | Single line text | Request reference, e.g. auto-numbered |
| StudentName / StudentID / Programme / Purpose / Remarks / StudentEmail | Text / Choice | From the Power Apps form |
| Status | Choice | Pending / Approved / Rejected |
| ApproverComments | Multiline text | Set by the approval step |
| GeneratedPDFLink | Hyperlink | Populated after PDF is generated |
Restrict "Contribute" access on this list to the app's service context — students should only be able to create items via the Power Apps form, not edit the list directly. Set unique permissions if needed.
Trigger — new item starts the flow
Step involved: a new entry in the SharePoint list triggers Power Automate.
Site Address = your school SharePoint site · List Name = Testimonial Requests
Use "When an item is created", not "created or modified" — otherwise every later status update (Approved/Rejected) will re-trigger the whole flow and loop.
Approval step — seek approval from admin
This is where the flow pauses and waits for a human decision.
Approve/Reject – First to respondTitle:
Testimonial request for @{triggerOutputs()?['body/StudentName']}Assigned to: admin's O365 email (or a distribution group of your 7 direct reports)
Details: include Student ID, Programme, Purpose and Remarks so the admin can decide without opening SharePoint.
- The admin receives a Teams/Outlook approval card with Approve and Reject buttons.
- The action returns an
Outcome(Approve/Reject) and anyCommentsthe admin typed. - Flow pauses here indefinitely until a response is given — no timeout is set by default; add one if requests must be actioned within X days.
Condition — either Approve or Reject
A standard Condition action reads the approval outcome and branches the flow.
Outcome (from the approval action) is equal to Approve
True branch — generate the testimonial
This matches the flow you already built (see screenshot): five actions run in sequence once the request is approved.
Status = "Approved" and ApproverComments on the same list item, using
ID from the trigger. This keeps the SharePoint list in sync before anything else happens.
.docx testimonial template and fills in the student's details.
Full walkthrough below ↓
/Generated Testimonials.File Name:
concat(triggerBody()?['StudentName'],'_',triggerBody()?['ID'],'.docx')File Content: the
Microsoft Word Document output from the Populate step above.
File: use the
ID output from "Create file" (not from the Populate step — a
common mistake, see Troubleshooting).
StudentEmail from the trigger · Subject: Your testimonial is readyAttachment name:
Testimonial.pdf · Attachment content: the File Content
output from "Convert Word Document to PDF".
Optionally add a sixth action here: Update item again to write the PDF's SharePoint URL into
GeneratedPDFLink, so admins can find it later without searching the folder.
Populate a Microsoft Word template — in detail
This is the action most people get stuck on. Here's the full setup, from template design to field mapping.
A. Prepare the Word template (one-time setup)
- Open Word (desktop) and go to File → Options → Customize Ribbon, tick Developer to show that tab.
- Design the testimonial layout with your school's letterhead, then click into each spot that needs student data (name, ID, programme, purpose, date, principal's name).
- For each spot, go to Developer → Plain Text Content Control, insert it, then click
Properties and give it a clear Tag and Title — e.g. tag
StudentName. This tag is exactly what Power Automate will map to. - Repeat for every dynamic field:
StudentID,Programme,Purpose,IssueDate,PrincipalName. - Save the file as
TestimonialTemplate.docxand upload it to a SharePoint document library, e.g./Templates. Keep this library separate from/Generated Testimonials.
B. Configure the action in Power Automate
| Field | Value |
|---|---|
| Location | SharePoint Site |
| Document Library | Templates |
| File | TestimonialTemplate.docx |
Once a valid file is selected, Power Automate auto-detects every content control in the template and shows them as input fields in the action — this is why the tags in step A matter: they become the field labels here.
| Content control (template) | Dynamic content (from trigger / Get item) |
|---|---|
StudentName | triggerBody()?['StudentName'] |
StudentID | triggerBody()?['StudentID'] |
Programme | triggerBody()?['Programme'] |
Purpose | triggerBody()?['Purpose'] |
IssueDate | formatDateTime(utcNow(),'d MMMM yyyy') |
PrincipalName | Static text, or pulled from a "Settings" SharePoint list |
C. What the action returns
The action outputs a field called Microsoft Word Document — this is the filled-in .docx
file content (base64), not yet saved anywhere. That's why Create file comes immediately after: it's
what actually persists the populated document into SharePoint so later steps (and people) can find it.
Premium connector. "Populate a Microsoft Word template" and "Convert Word Document to PDF" both use the Word Online (Business) connector, which is a premium connector. Your flow will need a Power Automate per-user or per-flow plan — the everyday Office 365 licence alone won't run it. Flag this to IT before building. See Licensing & permissions.
False branch — rejection
Two actions, mirroring the True branch but without document generation.
Status = "Rejected" and writes the admin's Comments into ApproverComments.PAIR.gov.sg — verifying the generated PDF
Cross-checking the testimonial's contents against the student records already uploaded to PAIR.gov.sg.
Power Automate has no built-in connector for PAIR.gov.sg, so this check needs to be handled as either a manual step or a custom integration — pick based on what PAIR.gov.sg exposes to your school:
Simplest, no extra build
Add an instruction in the approval email/Teams card asking the admin to open PAIR.gov.sg and confirm the student's name, ID and programme match before clicking Approve. This turns Step 05 into the verification point, and keeps the flow itself unchanged.
If PAIR.gov.sg offers an API/webhook
Insert an HTTP or Plumber.gov.sg-brokered call right after the trigger (Step 04) to fetch the student's record and compare it to the SharePoint entry before routing to approval. Confirm with GovTech/your IT team whether PAIR.gov.sg publishes an API for this — school accounts sometimes only get UI access, not programmatic access.
Don't guess at PAIR.gov.sg's integration capabilities — confirm with your IT/GovTech contact whether an API exists before committing to Option B. Until confirmed, run Option A so the pipeline still ships.
Troubleshooting
Issues that come up most often when building or running this flow.
| Symptom | Likely cause | Fix |
|---|---|---|
| "Populate a Microsoft Word template" errors on a content control name | Tag in the template doesn't match what the action expects, or the control was deleted/renamed after the action was configured | Re-open the template in Word, check Developer → content control Tag spelling, re-select the file in the action to refresh fields |
| "Convert Word Document to PDF" fails with file not found | Wrong File identifier — pointing to the Populate step's output instead of the saved file's ID |
Use the ID output from Create file, not from the Populate template step |
| Email attachment is blank or corrupted | Attachment content wasn't mapped to the correct File Content dynamic property |
In Send an email (V2), re-map the attachment content field from "Convert Word Document to PDF" output |
| Flow doesn't trigger on new submissions | SharePoint connection expired, or trigger set to "modified" causing confusion with re-runs | Reconnect the SharePoint connection under flow settings; confirm trigger is "When an item is created" |
| Approval card never reaches the admin | Admin's mailbox/Teams isn't licensed, or the "Assigned to" email has a typo | Verify the admin has an active O365 licence and check the exact email address in the approval action |
| Flow fails immediately with a connector/licensing error | Word Online (Business) actions are premium and no Power Automate premium licence is applied | Apply a per-user or per-flow premium plan; see Licensing & permissions |
Suggested team delegation
A way to split this build across your 7 direct reports so no single person is a bottleneck.
| Workstream | Owner focus | Needs training on |
|---|---|---|
| Power Apps form design + UX | 1 team member | Power Apps controls, form validation |
| SharePoint list schema + permissions | 1 team member | SharePoint columns, list permissions |
| Power Automate flow build (trigger → approval → condition) | 1–2 team members | Flow actions, dynamic content, expressions |
| Word template design (content controls) | 1 team member | Word Developer tab, content controls |
| UAT — test full path (approve + reject) | 1 team member | End-to-end testing, sample data |
| PAIR.gov.sg verification SOP + admin training | 1 team member | PAIR.gov.sg lookup process |
Since the Word template and premium-connector steps have the steepest learning curve, pair a less-technical staff member with a more technical one on that workstream rather than assigning it solo.
Licensing & permissions checklist
Confirm these before building, so the flow doesn't stall halfway through testing.
- Power Apps — standard O365 licence covers basic canvas apps writing to SharePoint; confirm your tenant's plan includes it.
- Power Automate premium connectors — "Populate a Microsoft Word template" and "Convert Word Document to PDF" require a per-user or per-flow premium plan. Flag this to IT/finance for procurement.
- SharePoint — Contribute access for the flow's connection account on both the list and the Templates/Generated Testimonials libraries.
- Outlook — the account sending emails (and the admin receiving approvals) needs an active Exchange Online mailbox.
- PAIR.gov.sg access — confirm which staff accounts have lookup rights, and whether API access is even offered to your school.