{"id":5744,"date":"2026-10-04T02:22:41","date_gmt":"2026-10-04T05:22:41","guid":{"rendered":"https:\/\/tucumandevelopers.com\/index.php\/2026\/10\/04\/turn-finished-visits-into-reviews-and-rebookings-an-n8n-follow-up-workflow-json-included\/"},"modified":"2026-10-04T02:22:41","modified_gmt":"2026-10-04T05:22:41","slug":"turn-finished-visits-into-reviews-and-rebookings-an-n8n-follow-up-workflow-json-included","status":"publish","type":"post","link":"https:\/\/tucumandevelopers.com\/index.php\/2026\/10\/04\/turn-finished-visits-into-reviews-and-rebookings-an-n8n-follow-up-workflow-json-included\/","title":{"rendered":"Turn finished visits into reviews and rebookings: an n8n follow-up workflow, JSON included"},"content":{"rendered":"<div>\n<div><\/div>\n<p>Edit the treatments and weeks to match your own list. Clinics translate<br \/> this trivially: check-up intervals and recall periods are exactly this<br \/> map. When a treatment is missing, the Default entry catches it, so no<br \/> customer silently drops out.<\/p>\n<h2> <a name=\"what-the-workflow-does\" href=\"#what-the-workflow-does\"> <\/a> What the workflow does <\/h2>\n<p>Seven nodes, one schedule trigger:<\/p>\n<ol>\n<li>Every 12 hours, a trigger fires.<\/li>\n<li>Completed visits are read. Demo rows in the JSON below; swap in your Google Sheet of completed visits.<\/li>\n<li>One code node picks the 20-30 hour window, picks review-ask versus rebook-nudge, computes the date, and builds the message.<\/li>\n<li>A placeholder send node stands in for WhatsApp Business Cloud, SMS, or email.<\/li>\n<li>An If node splits the two kinds.<\/li>\n<li>Two log nodes stamp the outcome: <code>review_sent<\/code> and <code>rebook_sent<\/code>, ready to wire into a sheet.<\/li>\n<\/ol>\n<p>The columns the source needs: <\/p>\n<div>\n<pre><code><span>appointment<\/span><span>_<\/span><span>id<\/span><span>,<\/span> <span>customer<\/span><span>_<\/span><span>name<\/span><span>,<\/span> <span>phone<\/span><span>,<\/span> <span>visited<\/span><span>_<\/span><span>at<\/span> <span>(<\/span><span>ISO<\/span><span>),<\/span> <span>treatment<\/span><span>,<\/span> <span>practitioner<\/span><span>,<\/span> <span>first<\/span><span>_<\/span><span>visit<\/span> <span>APT<\/span><span>-<\/span><span>3001<\/span><span>,<\/span> <span>Anna<\/span> <span>Voorbeeld<\/span><span>,<\/span> <span>+<\/span><span>316<\/span><span>****<\/span><span>5678<\/span><span>,<\/span> <span>2026-10-01T09:00:00Z<\/span><span>,<\/span> <span>Hair<\/span> <span>treatment<\/span><span>,<\/span> <span>Stylist<\/span> <span>A<\/span><span>,<\/span> <span>false<\/span> <span>APT<\/span><span>-<\/span><span>3002<\/span><span>,<\/span> <span>Tom<\/span> <span>Voorbeeld<\/span><span>,<\/span> <span>+<\/span><span>316<\/span><span>****<\/span><span>5432<\/span><span>,<\/span> <span>2026-10-03T08:00:00Z<\/span><span>,<\/span> <span>Haircut<\/span><span>,<\/span> <span>Stylist<\/span> <span>B<\/span><span>,<\/span> <span>true<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<h2> <a name=\"the-code-node-that-matters\" href=\"#the-code-node-that-matters\"> <\/a> The code node that matters <\/h2>\n<p>Window, kind, date, and message in one pass: <\/p>\n<div>\n<pre><code><span>const<\/span> <span>items<\/span> <span>=<\/span> <span>$input<\/span><span>.<\/span><span>all<\/span><span>();<\/span> <span>const<\/span> <span>now<\/span> <span>=<\/span> <span>Date<\/span><span>.<\/span><span>now<\/span><span>();<\/span> <span>const<\/span> <span>out<\/span> <span>=<\/span> <span>[];<\/span> <span>const<\/span> <span>INTERVAL_WEEKS<\/span> <span>=<\/span> <span>{<\/span> <span>'<\/span><span>Hair treatment<\/span><span>'<\/span><span>:<\/span> <span>12<\/span><span>,<\/span> <span>'<\/span><span>Color touch-up<\/span><span>'<\/span><span>:<\/span> <span>6<\/span><span>,<\/span> <span>'<\/span><span>Haircut<\/span><span>'<\/span><span>:<\/span> <span>5<\/span><span>,<\/span> <span>'<\/span><span>Check-up<\/span><span>'<\/span><span>:<\/span> <span>6<\/span><span>,<\/span> <span>'<\/span><span>Default<\/span><span>'<\/span><span>:<\/span> <span>8<\/span> <span>};<\/span> <span>for <\/span><span>(<\/span><span>const<\/span> <span>item<\/span> <span>of<\/span> <span>items<\/span><span>)<\/span> <span>{<\/span> <span>const<\/span> <span>r<\/span> <span>=<\/span> <span>item<\/span><span>.<\/span><span>json<\/span><span>;<\/span> <span>const<\/span> <span>hoursAgo<\/span> <span>=<\/span> <span>(<\/span><span>now<\/span> <span>-<\/span> <span>new<\/span> <span>Date<\/span><span>(<\/span><span>r<\/span><span>.<\/span><span>visited_at<\/span><span>).<\/span><span>getTime<\/span><span>())<\/span> <span>\/<\/span> <span>3600000<\/span><span>;<\/span> <span>if <\/span><span>(<\/span><span>hoursAgo<\/span> <span>&lt;<\/span> <span>20<\/span> <span>||<\/span> <span>hoursAgo<\/span> <span>&gt;<\/span> <span>30<\/span><span>)<\/span> <span>continue<\/span><span>;<\/span> <span>const<\/span> <span>weeks<\/span> <span>=<\/span> <span>INTERVAL_WEEKS<\/span><span>[<\/span><span>r<\/span><span>.<\/span><span>treatment<\/span><span>]<\/span> <span>||<\/span> <span>INTERVAL_WEEKS<\/span><span>[<\/span><span>'<\/span><span>Default<\/span><span>'<\/span><span>];<\/span> <span>const<\/span> <span>rebookDate<\/span> <span>=<\/span> <span>new<\/span> <span>Date<\/span><span>(<\/span><span>now<\/span> <span>+<\/span> <span>weeks<\/span> <span>*<\/span> <span>7<\/span> <span>*<\/span> <span>24<\/span> <span>*<\/span> <span>3600<\/span> <span>*<\/span> <span>1000<\/span><span>);<\/span> <span>const<\/span> <span>rebookStr<\/span> <span>=<\/span> <span>rebookDate<\/span><span>.<\/span><span>toLocaleDateString<\/span><span>(<\/span><span>'<\/span><span>en-GB<\/span><span>'<\/span><span>,<\/span> <span>{<\/span> <span>weekday<\/span><span>:<\/span> <span>'<\/span><span>long<\/span><span>'<\/span><span>,<\/span> <span>day<\/span><span>:<\/span> <span>'<\/span><span>numeric<\/span><span>'<\/span><span>,<\/span> <span>month<\/span><span>:<\/span> <span>'<\/span><span>long<\/span><span>'<\/span> <span>});<\/span> <span>let<\/span> <span>message<\/span><span>;<\/span> <span>if <\/span><span>(<\/span><span>r<\/span><span>.<\/span><span>first_visit<\/span><span>)<\/span> <span>{<\/span> <span>message<\/span> <span>=<\/span> <span>'<\/span><span>Hi <\/span><span>'<\/span> <span>+<\/span> <span>r<\/span><span>.<\/span><span>customer_name<\/span> <span>+<\/span> <span>'<\/span><span>, thanks for your first visit! How was it? A review helps us a lot: REVIEWLINK. It takes 1 minute.<\/span><span>'<\/span><span>;<\/span> <span>}<\/span> <span>else<\/span> <span>{<\/span> <span>message<\/span> <span>=<\/span> <span>'<\/span><span>Hi <\/span><span>'<\/span> <span>+<\/span> <span>r<\/span><span>.<\/span><span>customer_name<\/span> <span>+<\/span> <span>'<\/span><span>, great to see you again! Your next <\/span><span>'<\/span> <span>+<\/span> <span>r<\/span><span>.<\/span><span>treatment<\/span> <span>+<\/span> <span>'<\/span><span> is due in about <\/span><span>'<\/span> <span>+<\/span> <span>weeks<\/span> <span>+<\/span> <span>'<\/span><span> weeks (<\/span><span>'<\/span> <span>+<\/span> <span>rebookStr<\/span> <span>+<\/span> <span>'<\/span><span>). Want to reserve a spot now? Reply BOOK.<\/span><span>'<\/span><span>;<\/span> <span>}<\/span> <span>out<\/span><span>.<\/span><span>push<\/span><span>({<\/span> <span>json<\/span><span>:<\/span> <span>{<\/span> <span>appointment_id<\/span><span>:<\/span> <span>r<\/span><span>.<\/span><span>appointment_id<\/span><span>,<\/span> <span>customer_name<\/span><span>:<\/span> <span>r<\/span><span>.<\/span><span>customer_name<\/span><span>,<\/span> <span>to<\/span><span>:<\/span> <span>r<\/span><span>.<\/span><span>phone<\/span><span>,<\/span> <span>channel<\/span><span>:<\/span> <span>'<\/span><span>whatsapp<\/span><span>'<\/span><span>,<\/span> <span>kind<\/span><span>:<\/span> <span>r<\/span><span>.<\/span><span>first_visit<\/span> <span>?<\/span> <span>'<\/span><span>review_ask<\/span><span>'<\/span> <span>:<\/span> <span>'<\/span><span>rebook_nudge<\/span><span>'<\/span><span>,<\/span> <span>rebook_weeks<\/span><span>:<\/span> <span>weeks<\/span><span>,<\/span> <span>rebook_date<\/span><span>:<\/span> <span>rebookDate<\/span><span>.<\/span><span>toISOString<\/span><span>(),<\/span> <span>message<\/span><span>:<\/span> <span>message<\/span> <span>}<\/span> <span>});<\/span> <span>}<\/span> <span>return<\/span> <span>out<\/span><span>;<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>The <code>continue<\/code> on the window check keeps every run idempotent: rows<br \/> outside the window drop out before a message exists, and rows older<br \/> than 30 hours are gone forever, which is correct. You had one morning<br \/> to catch that customer and the workflow used it.<\/p>\n<h2> <a name=\"close-the-loop-on-book-replies\" href=\"#close-the-loop-on-book-replies\"> <\/a> Close the loop on BOOK replies <\/h2>\n<p>The rebook log node is where the series connects. When a customer<br \/> replies BOOK, that reply should land in a booking intake flow with the<br \/> suggested slot prefilled, not in an inbox. My booking intake build<br \/> (validated webhook, field checks, instant structured responses) is in<br \/> the pack linked below; wiring the BOOK reply into its webhook is two<br \/> nodes.<\/p>\n<h2> <a name=\"test-it-without-sending-anything\" href=\"#test-it-without-sending-anything\"> <\/a> Test it without sending anything <\/h2>\n<p>The JSON below has demo data wired in. Import it into n8n, open the<br \/> demo visits node, and shift <code>visited_at<\/code> to roughly 26 hours ago (the<br \/> demo rows already sit there relative to now). Execute and watch the If<br \/> node split the first-timer from the regular. No message leaves: the<br \/> send node is a placeholder by design.<\/p>\n<h2> <a name=\"the-complete-workflow-json\" href=\"#the-complete-workflow-json\"> <\/a> The complete workflow JSON <\/h2>\n<p>Import into n8n (Workflows, Import from File), replace the demo source<br \/> with your completed-visits sheet, and put a real send node in the<br \/> middle. Point REVIEWLINK at your review page: <\/p>\n<div>\n<pre><code><span>{<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Send post-visit review asks and rebooking nudges\"<\/span><span>,<\/span><span> <\/span><span>\"nodes\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"rule\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"interval\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"field\"<\/span><span>:<\/span><span> <\/span><span>\"hours\"<\/span><span>,<\/span><span> <\/span><span>\"hoursInterval\"<\/span><span>:<\/span><span> <\/span><span>12<\/span><span> <\/span><span>}<\/span><span> <\/span><span>]<\/span><span> <\/span><span>}<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"d1000000-0000-4000-8000-000000000001\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Every 12 hours\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.scheduleTrigger\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>1.2<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>-200<\/span><span>,<\/span><span> <\/span><span>0<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"jsCode\"<\/span><span>:<\/span><span> <\/span><span>\"\/\/ DEMO SOURCE. Replace with your Google Sheet of completed visits.<\/span><span>\\n<\/span><span>\/\/ Columns: appointment_id, customer_name, phone, visited_at (ISO), treatment, practitioner, first_visit<\/span><span>\\n<\/span><span>const demoRows = [<\/span><span>\\n<\/span><span> {<\/span><span>\\n<\/span><span> appointment_id: 'APT-3001',<\/span><span>\\n<\/span><span> customer_name: 'Anna Voorbeeld',<\/span><span>\\n<\/span><span> phone: '+316****5678',<\/span><span>\\n<\/span><span> visited_at: new Date(Date.now() - 26 * 3600 * 1000).toISOString(),<\/span><span>\\n<\/span><span> treatment: 'Hair treatment',<\/span><span>\\n<\/span><span> practitioner: 'Stylist A',<\/span><span>\\n<\/span><span> first_visit: false<\/span><span>\\n<\/span><span> },<\/span><span>\\n<\/span><span> {<\/span><span>\\n<\/span><span> appointment_id: 'APT-3002',<\/span><span>\\n<\/span><span> customer_name: 'Tom Voorbeeld',<\/span><span>\\n<\/span><span> phone: '+316****5432',<\/span><span>\\n<\/span><span> visited_at: new Date(Date.now() - 3 * 3600 * 1000).toISOString(),<\/span><span>\\n<\/span><span> treatment: 'Haircut',<\/span><span>\\n<\/span><span> practitioner: 'Stylist B',<\/span><span>\\n<\/span><span> first_visit: true<\/span><span>\\n<\/span><span> }<\/span><span>\\n<\/span><span>];<\/span><span>\\n<\/span><span>return demoRows.map((row) =&gt; ({ json: row }));\"<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"d1000000-0000-4000-8000-000000000002\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Completed visits (demo data)\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.code\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>2<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>20<\/span><span>,<\/span><span> <\/span><span>0<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"jsCode\"<\/span><span>:<\/span><span> <\/span><span>\"\/\/ Pick visits that ended 20..30 hours ago (the sweet spot: next morning).<\/span><span>\\n<\/span><span>\/\/ First-time customers get the review ask; regulars get a rebooking nudge<\/span><span>\\n<\/span><span>\/\/ with their usual interval.<\/span><span>\\n<\/span><span>const items = $input.all();<\/span><span>\\n<\/span><span>const now = Date.now();<\/span><span>\\n<\/span><span>const out = [];<\/span><span>\\n<\/span><span>const INTERVAL_WEEKS = { 'Hair treatment': 12, 'Color touch-up': 6, 'Haircut': 5, 'Check-up': 6, 'Default': 8 };<\/span><span>\\n<\/span><span>for (const item of items) {<\/span><span>\\n<\/span><span> const r = item.json;<\/span><span>\\n<\/span><span> const hoursAgo = (now - new Date(r.visited_at).getTime()) \/ 3600000;<\/span><span>\\n<\/span><span> if (hoursAgo &lt; 20 || hoursAgo &gt; 30) continue;<\/span><span>\\n<\/span><span> const weeks = INTERVAL_WEEKS[r.treatment] || INTERVAL_WEEKS['Default'];<\/span><span>\\n<\/span><span> const rebookDate = new Date(now + weeks * 7 * 24 * 3600 * 1000);<\/span><span>\\n<\/span><span> const rebookStr = rebookDate.toLocaleDateString('en-GB', { weekday: 'long', day: 'numeric', month: 'long' });<\/span><span>\\n<\/span><span> let message;<\/span><span>\\n<\/span><span> if (r.first_visit) {<\/span><span>\\n<\/span><span> message = 'Hi ' + r.customer_name + ', thanks for your first visit! How was it? A review helps us a lot: REVIEWLINK. It takes 1 minute.';<\/span><span>\\n<\/span><span> } else {<\/span><span>\\n<\/span><span> message = 'Hi ' + r.customer_name + ', great to see you again! Your next ' + r.treatment + ' is due in about ' + weeks + ' weeks (' + rebookStr + '). Want to reserve a spot now? Reply BOOK.';<\/span><span>\\n<\/span><span> }<\/span><span>\\n<\/span><span> out.push({<\/span><span>\\n<\/span><span> json: {<\/span><span>\\n<\/span><span> appointment_id: r.appointment_id,<\/span><span>\\n<\/span><span> customer_name: r.customer_name,<\/span><span>\\n<\/span><span> to: r.phone,<\/span><span>\\n<\/span><span> channel: 'whatsapp',<\/span><span>\\n<\/span><span> kind: r.first_visit ? 'review_ask' : 'rebook_nudge',<\/span><span>\\n<\/span><span> rebook_weeks: weeks,<\/span><span>\\n<\/span><span> rebook_date: rebookDate.toISOString(),<\/span><span>\\n<\/span><span> message: message<\/span><span>\\n<\/span><span> }<\/span><span>\\n<\/span><span> });<\/span><span>\\n<\/span><span>}<\/span><span>\\n<\/span><span>return out;\"<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"d1000000-0000-4000-8000-000000000003\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Pick window + build message\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.code\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>2<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>240<\/span><span>,<\/span><span> <\/span><span>0<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"jsCode\"<\/span><span>:<\/span><span> <\/span><span>\"\/\/ Placeholder for the send node (WhatsApp Business Cloud \/ SMS \/ email).<\/span><span>\\n<\/span><span>const items = $input.all();<\/span><span>\\n<\/span><span>return items.map((item) =&gt; ({<\/span><span>\\n<\/span><span> json: { ...item.json, sent_at: new Date().toISOString(), transport: 'demo' }<\/span><span>\\n<\/span><span>}));\"<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"d1000000-0000-4000-8000-000000000004\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Send follow-up (replace me)\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.code\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>2<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>460<\/span><span>,<\/span><span> <\/span><span>0<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"conditions\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"options\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"caseSensitive\"<\/span><span>:<\/span><span> <\/span><span>true<\/span><span>,<\/span><span> <\/span><span>\"leftValue\"<\/span><span>:<\/span><span> <\/span><span>\"\"<\/span><span>,<\/span><span> <\/span><span>\"typeValidation\"<\/span><span>:<\/span><span> <\/span><span>\"strict\"<\/span><span>,<\/span><span> <\/span><span>\"version\"<\/span><span>:<\/span><span> <\/span><span>2<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"conditions\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"c1\"<\/span><span>,<\/span><span> <\/span><span>\"leftValue\"<\/span><span>:<\/span><span> <\/span><span>\"={{ $json.kind }}\"<\/span><span>,<\/span><span> <\/span><span>\"rightValue\"<\/span><span>:<\/span><span> <\/span><span>\"review_ask\"<\/span><span>,<\/span><span> <\/span><span>\"operator\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"string\"<\/span><span>,<\/span><span> <\/span><span>\"operation\"<\/span><span>:<\/span><span> <\/span><span>\"equals\"<\/span><span> <\/span><span>}<\/span><span> <\/span><span>}<\/span><span> <\/span><span>],<\/span><span> <\/span><span>\"combinator\"<\/span><span>:<\/span><span> <\/span><span>\"and\"<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"options\"<\/span><span>:<\/span><span> <\/span><span>{}<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"d1000000-0000-4000-8000-000000000005\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Review ask?\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.if\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>2.2<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>680<\/span><span>,<\/span><span> <\/span><span>0<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"jsCode\"<\/span><span>:<\/span><span> <\/span><span>\"\/\/ Review-ask outcomes: log which channel converted (wire a Sheet write here).<\/span><span>\\n<\/span><span>const items = $input.all();<\/span><span>\\n<\/span><span>return items.map((item) =&gt; ({ json: { ...item.json, logged_as: 'review_sent' } }));\"<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"d1000000-0000-4000-8000-000000000006\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Log review ask\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.code\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>2<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>900<\/span><span>,<\/span><span> <\/span><span>-100<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"jsCode\"<\/span><span>:<\/span><span> <\/span><span>\"\/\/ Rebook-nudge outcomes: a BOOK reply should trigger your booking intake<\/span><span>\\n<\/span><span>\/\/ workflow with the suggested slot prefilled.<\/span><span>\\n<\/span><span>const items = $input.all();<\/span><span>\\n<\/span><span>return items.map((item) =&gt; ({ json: { ...item.json, logged_as: 'rebook_sent' } }));\"<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"d1000000-0000-4000-8000-000000000007\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Log rebook nudge\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.code\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>2<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>900<\/span><span>,<\/span><span> <\/span><span>100<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"content\"<\/span><span>:<\/span><span> <\/span><span>\"## Send post-visit review asks and rebooking nudges<\/span><span>\\n\\n<\/span><span>### How it works<\/span><span>\\n\\n<\/span><span>Every 12 hours the workflow reads completed visits and picks the ones that ended 20 to 30 hours ago: next-morning timing, high response rates. First-time customers get a review ask. Regulars get a rebooking nudge with the interval their treatment usually needs. Each message is built with the customer name, the treatment, and the suggested rebooking date, then handed to your WhatsApp, SMS, or email send node.<\/span><span>\\n\\n<\/span><span>### Setup steps<\/span><span>\\n\\n<\/span><span>- Replace the demo visits node with your Google Sheets source of completed visits.<\/span><span>\\n<\/span><span>- Replace the send placeholder with a WhatsApp Business Cloud, SMS, or email node.<\/span><span>\\n<\/span><span>- Point REVIEWLINK in the review message at your review page.<\/span><span>\\n\\n<\/span><span>### Customization<\/span><span>\\n\\n<\/span><span>Treatment intervals live in the INTERVAL_WEEKS map in the window-picker node. The 20-30 hour window and the 12-hour schedule fit most salons and clinics; shift them for your own rhythm.<\/span><span>\\n\\n<\/span><span>### Requirements<\/span><span>\\n\\n<\/span><span>n8n on any plan. The demo data runs without credentials. For production you need a Google Sheets credential and a WhatsApp Business Cloud, SMS, or email send credential.\"<\/span><span>,<\/span><span> <\/span><span>\"width\"<\/span><span>:<\/span><span> <\/span><span>600<\/span><span>,<\/span><span> <\/span><span>\"height\"<\/span><span>:<\/span><span> <\/span><span>820<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"cccc0000-0000-4000-8000-0000000000f1\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Sticky Note 00f1\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.stickyNote\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>1<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>-960<\/span><span>,<\/span><span> <\/span><span>-300<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"content\"<\/span><span>:<\/span><span> <\/span><span>\"## 1. Read visits<\/span><span>\\n<\/span><span>Demo rows stand in for your Sheet of completed visits. Swap the node, keep the columns.\"<\/span><span>,<\/span><span> <\/span><span>\"color\"<\/span><span>:<\/span><span> <\/span><span>7<\/span><span>,<\/span><span> <\/span><span>\"width\"<\/span><span>:<\/span><span> <\/span><span>455<\/span><span>,<\/span><span> <\/span><span>\"height\"<\/span><span>:<\/span><span> <\/span><span>420<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"cccc0000-0000-4000-8000-0000000000f2\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Sticky Note 00f2\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.stickyNote\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>1<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>-320<\/span><span>,<\/span><span> <\/span><span>-200<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"content\"<\/span><span>:<\/span><span> <\/span><span>\"## 2. Pick window + build message<\/span><span>\\n<\/span><span>20-30 hours after the visit. First visit: review ask. Regular: rebooking nudge with treatment interval.\"<\/span><span>,<\/span><span> <\/span><span>\"color\"<\/span><span>:<\/span><span> <\/span><span>7<\/span><span>,<\/span><span> <\/span><span>\"width\"<\/span><span>:<\/span><span> <\/span><span>400<\/span><span>,<\/span><span> <\/span><span>\"height\"<\/span><span>:<\/span><span> <\/span><span>420<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"cccc0000-0000-4000-8000-0000000000f3\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Sticky Note 00f3\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.stickyNote\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>1<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>175<\/span><span>,<\/span><span> <\/span><span>-200<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"parameters\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"content\"<\/span><span>:<\/span><span> <\/span><span>\"## 3. Send + log<\/span><span>\\n<\/span><span>Replace the placeholder with your real send node. Both branches log what went out.\"<\/span><span>,<\/span><span> <\/span><span>\"color\"<\/span><span>:<\/span><span> <\/span><span>7<\/span><span>,<\/span><span> <\/span><span>\"width\"<\/span><span>:<\/span><span> <\/span><span>515<\/span><span>,<\/span><span> <\/span><span>\"height\"<\/span><span>:<\/span><span> <\/span><span>580<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"id\"<\/span><span>:<\/span><span> <\/span><span>\"cccc0000-0000-4000-8000-0000000000f4\"<\/span><span>,<\/span><span> <\/span><span>\"name\"<\/span><span>:<\/span><span> <\/span><span>\"Sticky Note 00f4\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"n8n-nodes-base.stickyNote\"<\/span><span>,<\/span><span> <\/span><span>\"typeVersion\"<\/span><span>:<\/span><span> <\/span><span>1<\/span><span>,<\/span><span> <\/span><span>\"position\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>615<\/span><span>,<\/span><span> <\/span><span>-200<\/span><span> <\/span><span>]<\/span><span> <\/span><span>}<\/span><span> <\/span><span>],<\/span><span> <\/span><span>\"connections\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"Every 12 hours\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"main\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>[<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"node\"<\/span><span>:<\/span><span> <\/span><span>\"Completed visits (demo data)\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"main\"<\/span><span>,<\/span><span> <\/span><span>\"index\"<\/span><span>:<\/span><span> <\/span><span>0<\/span><span> <\/span><span>}<\/span><span> <\/span><span>]<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"Completed visits (demo data)\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"main\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>[<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"node\"<\/span><span>:<\/span><span> <\/span><span>\"Pick window + build message\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"main\"<\/span><span>,<\/span><span> <\/span><span>\"index\"<\/span><span>:<\/span><span> <\/span><span>0<\/span><span> <\/span><span>}<\/span><span> <\/span><span>]<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"Pick window + build message\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"main\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>[<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"node\"<\/span><span>:<\/span><span> <\/span><span>\"Send follow-up (replace me)\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"main\"<\/span><span>,<\/span><span> <\/span><span>\"index\"<\/span><span>:<\/span><span> <\/span><span>0<\/span><span> <\/span><span>}<\/span><span> <\/span><span>]<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"Send follow-up (replace me)\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"main\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>[<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"node\"<\/span><span>:<\/span><span> <\/span><span>\"Review ask?\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"main\"<\/span><span>,<\/span><span> <\/span><span>\"index\"<\/span><span>:<\/span><span> <\/span><span>0<\/span><span> <\/span><span>}<\/span><span> <\/span><span>]<\/span><span> <\/span><span>]<\/span><span> <\/span><span>},<\/span><span> <\/span><span>\"Review ask?\"<\/span><span>:<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"main\"<\/span><span>:<\/span><span> <\/span><span>[<\/span><span> <\/span><span>[<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"node\"<\/span><span>:<\/span><span> <\/span><span>\"Log review ask\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"main\"<\/span><span>,<\/span><span> <\/span><span>\"index\"<\/span><span>:<\/span><span> <\/span><span>0<\/span><span> <\/span><span>}<\/span><span> <\/span><span>],<\/span><span> <\/span><span>[<\/span><span> <\/span><span>{<\/span><span> <\/span><span>\"node\"<\/span><span>:<\/span><span> <\/span><span>\"Log rebook nudge\"<\/span><span>,<\/span><span> <\/span><span>\"type\"<\/span><span>:<\/span><span> <\/span><span>\"main\"<\/span><span>,<\/span><span> <\/span><span>\"index\"<\/span><span>:<\/span><span> <\/span><span>0<\/span><span> <\/span><span>}<\/span><span> <\/span><span>]<\/span><span> <\/span><span>]<\/span><span> <\/span><span>}<\/span><span> <\/span><span>}<\/span><span> <\/span><span>}<\/span><span> <\/span><\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<h2> <a name=\"where-this-fits\" href=\"#where-this-fits\"> <\/a> Where this fits <\/h2>\n<p>This is the fourth full build in the series. <a href=\"https:\/\/dev.to\/vlotstroom\/appointment-reminders-that-cut-no-shows-a-complete-n8n-workflow-json-included-k0i\">Appointment reminders<br \/> with a no-double-send<br \/> guard<\/a>,<br \/> <a href=\"https:\/\/dev.to\/vlotstroom\/fill-cancelled-appointments-automatically-a-ranked-waitlist-n8n-workflow-json-included-2j3n\">waitlist backfill that fills cancelled slots<br \/> automatically<\/a>,<br \/> and <a href=\"https:\/\/dev.to\/vlotstroom\/recover-no-show-fees-without-the-awkward-conversation-an-n8n-escalation-ladder-json-included-48d1\">fee recovery with a polite escalation<br \/> ladder<\/a><br \/> came before. This one grows the good side of the ledger: reviews and<br \/> rebookings instead of losses. If you want the Dutch-language versions<br \/> plus the surrounding pack (booking intake, KPI digest) in one download,<br \/> it is here: <a href=\"https:\/\/vlotstream.gumroad.com\/l\/rhmxw\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/vlotstream.gumroad.com\/l\/rhmxw<\/a><\/p>\n<h2> <a name=\"free-companion-tool\" href=\"#free-companion-tool\"> <\/a> Free companion tool <\/h2>\n<p>Want the number before the workflow? I put the no-show math in a small<br \/> free calculator (EN\/NL, no signup, runs in your browser): <a href=\"https:\/\/vlotstroom.github.io\/noshow-calculator\/\" target=\"_blank\" rel=\"noopener noreferrer\">no-show cost<br \/> calculator<\/a><\/p>\n<\/p><\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Fuente: <a href=\"https:\/\/dev.to\/vlotstroom\/turn-finished-visits-into-reviews-and-rebookings-an-n8n-follow-up-workflow-json-included-1ca2\">Art\u00edculo original<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Edit the treatments and weeks to match your own list. Clinics translate this trivially: check-up intervals and recall periods are exactly this map. When a treatment is missing, the Default entry catches it, so no customer silently drops out. What the workflow does Seven nodes, one schedule trigger: Every 12 hours, a trigger fires. Completed [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":5743,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"webixso_pending_account_ids":""},"categories":[41],"tags":[],"class_list":["post-5744","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devto"],"jetpack_publicize_connections":[],"_links":{"self":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/5744","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/comments?post=5744"}],"version-history":[{"count":0,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/5744\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media\/5743"}],"wp:attachment":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media?parent=5744"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/categories?post=5744"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/tags?post=5744"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}