Make.com test project · built on sample data
Your scenario, built and running end to end on a synthetic student. When a course is purchased in MindBody, the automation reads the booking state (it never books sessions itself), matches the right HubSpot segment by date range, updates the contact, logs an audit row, alerts the VA when the rules call for it, and drafts the confirmation for a human to approve. Where a person should decide, it stops and asks.
Built for the specification you posted publicly on Make's Hire a Pro board, then updated to match the revised spec. No prior MindBody or StartIntegrate client build is claimed, so rather than describe work you cannot verify, here is your scenario running on invented data.
Updated July 8 to match the revised specification.
Why a working build instead of a portfolio link
You asked whether respondents have built with the StartIntegrate / MAXMEL MindBody connector, how the automation would avoid double-processing the same student, and how it would pick the right segment when the segment names are inconsistent. The most honest answer is the build itself. Everything below runs on invented sample data. There are no live keys and no calls to your MindBody or HubSpot account. Where this design earns its keep is the read-only booking check, the deduplication, and the date-range segment match, and each is called out inline.
A parent buys a five session course in MindBody. Sessions are still booked by hand in MindBody; the automation only reads whether a session has been booked, then keeps HubSpot and the records in step. The hard parts are getting the timing right, not processing the same purchase twice, and matching the one correct segment out of a set of inconsistently named lists.
Every box is something the scenario does. Every branch to the right is a place where it deliberately stops and hands the case to a person instead of guessing.
The three stops on the right are what the revised spec is really about: nothing booked yet, a segment the automation cannot resolve to exactly one list, and a purchase that was already processed. Each is walked through below.
gateway:CustomWebHook · receives clientSale.created
Before the bundle is trusted, the scenario verifies the X-Mindbody-Signature header (HMAC-SHA256 of the raw body with the subscription's messageSignatureKey).
{
"messageId": "ASReXAmM8JmZfLBb2M2zBcp7Sm5aQ",
"eventId": "clientSale.created",
"eventSchemaVersion": 1,
"eventInstanceOriginationDateTime": "2026-07-03T14:12:05Z",
"eventData": {
"siteId": 123456,
"clientId": "100024816",
"saleId": 987654,
"client": {
"name": "Maya Chen",
"email": "maya.chen@example.com"
},
"items": [
{
"id": 5501,
"type": "Service",
"name": "HS Study Skills and Strategies Course",
"amountPaid": 495.00
}
]
}
}
// header X-Mindbody-Signature: sha256=6f1e... verified against the subscription keyOne honest production note, verified against the real MindBody sandbox: the live sale event may not carry the client email. When it does not, a GET /client/clients lookup on the clientId resolves it before the HubSpot steps. The sample event here includes it, so module 2 reads it directly.
hubspotcrm:MakeAPICall · POST /crm/v3/objects/contacts/search
Before anything else, the scenario reads the contact by email to pull one checkbox: Manual enrollment - skip automation. Staff tick it on the contact before the purchase, so there is no race. The same read also pulls the current courses-taken list (so step 2 can append rather than overwrite) and the contact id.
// override read from the contact
override = if( manual_enrollment_skip_automation = "true"; "true"; "false" )
// checked -> skip ONLY the step 1 booking check; steps 2-6 still run
// unchecked -> run step 1 (the wait and booking check below)This is the escape hatch for the cases where staff already know the enrollment is correct and just want the records updated. It never skips steps 2 through 6.
util:FunctionSleep ×2 then http GET /client/clientvisits
Parents usually book their sessions a few minutes after buying, so the scenario waits about ten minutes before it looks (two chained Sleep modules, because a single Sleep maxes out at 300 seconds). When the override is set, the wait collapses to one second and the booking check is skipped.
Parents book out of order, so the question is not "is session one booked" but "is any session booked for this course and week". The forward window returns future bookings; the scenario keeps only those whose status is Booked.
// keep future bookings whose AppointmentStatus is "Booked"
// (real-sandbox trap: the field is AppointmentStatus, not Status,
// and Missed is TRUE on future bookings, so never count via Missed)
bookingCount = length( Visits where AppointmentStatus = "Booked" )
// 1 booked session found -> StartDateTime 2026-07-13 -> carry that date forwardZero booked is a normal outcome, not a failure. If nothing is booked after the wait, the scenario emails the parent to ask for their preferred dates and then stops. Staff complete the booking by hand; the scenario does not re-trigger itself. For the AI Workshop, a single-session course, no session at purchase is the usual case, so that path is the expected one there.
hubspotcrm:MakeAPICall · GET /crm/v3/lists/{listId}/memberships
A parent can book several sessions of one course in a single sitting, and each booking can fire the purchase flow. Only the first should run steps 2 through 6. So before those steps, the scenario checks whether the student is already a member of the target segment for this course and week. If they are, it stops.
// is the contact already in the target list?
// yes -> STOP (an earlier booking in the same purchase already processed it)
// no -> proceed to steps 2-6
already_member = contains( target_list.memberships; contactId )Membership is read from a static (manual or snapshot) list through the HubSpot v3 Lists API, which is immediate rather than lag prone. This is what makes a repeat delivery of the same purchase a safe no-op.
hubspotcrm lists index then segment resolver (date-range match)
Your segment lists are named inconsistently today. A tolerant match is the whole problem. The scenario pulls the lists index, then keeps the list whose parsed date range contains the booked session's date and whose tokens match the course level and delivery. Here is the same set of lists the resolver sees, and which one wins for a session on 2026-07-13, HS level:
5012 wins: its range 7/6 to 7/17/2026 contains 7/13, and the name carries the HS token. 4488 is a different course and its range ends 6/13, before 7/13. 5090 contains 7/13 by date, but its level token is MS, not HS. Containment plus the level and delivery tokens leaves exactly one list.
hubspotcrm:upsertAContact
The course name is appended to the multi-select courses-taken property, so every prior course is kept and this one is added (and not duplicated if it is already there). Only coursesync_ properties are written.
{
"coursesync_enrollment_status": "enrolled",
"coursesync_last_sync": "2026-07-03T14:22:07Z",
"coursesync_course_name": "HS Study Skills and Strategies Course",
"coursesync_courses_taken": "Prior Course A;HS Study Skills and Strategies Course"
}
// BEFORE: "Prior Course A" -> AFTER: prior course kept, this one appendedhubspotcrm:addMembersToAList
The contact is added to the list the resolver matched (list 5012 here), using HubSpot's native Add Members to a List module. This is the current supported replacement for the older add-to-list module HubSpot deprecated in September 2025, and this membership is also what the dedup check reads on any later booking of the same course.
Needs the crm.lists read and write scopes on the HubSpot connection. A contacts-only connection reads and writes contacts fine but returns a 403 here, which halts the run, so the connection carries those scopes explicitly.
google-sheets:addRow
One row per processed purchase, so there is a plain record outside the two systems. The revised spec adds a column: MB Enrollment, which reads Automated when a booking was found or Manual for the override and zero-booking paths.
{
"Timestamp": "2026-07-03 14:22:07",
"Student": "Maya Chen",
"Course": "HS Study Skills and Strategies Course",
"Segment": "7/6-7/17/2026 HS Class",
"MB Enrollment": "Automated",
"SaleId": "987654"
}google-email:sendAnEmail · with a filter
This step is conditional. The VA is alerted only for the HWC three-session expiration extension check, which applies to MS or HS Study Skills and Strategies, in-person, in the summer. College, ES, Remote, Writing, Growth Strategies, and the AI Workshop do not page the VA.
// VA alert fires only when ALL are true
vaEligible = (MS or HS Study Skills) AND In-Person AND session month is 06, 07, or 08
// Maya: HS Study Skills, In-Person, session 2026-07-13 -> VA alertedThe VA recipient is a placeholder, pending the hire. The channel is easy to point at whatever the VA uses, including a Slack message or a task.
hubspotcrm:MakeAPICall · Single-Send template
The confirmation is built from your HubSpot template, with the course name and segment merged in, but it is delivered to the admin as a draft for review rather than sent straight to the family. The subject is prefixed DRAFT COURSE CONF: so it is obvious in the inbox and a human approves the wording before the family sees it.
The primary walk above is the everyday case. The revised spec is really about the paths where the automation must be careful, so the router covers each explicitly.
No session booked and no override set: email the parent to ask for their dates, then stop. Staff finish the booking by hand and the scenario does not re-trigger. This is the normal case for the single-session AI Workshop.
The student is already a member of the target segment, because an earlier booking in the same purchase already ran. The scenario stops before steps 2 through 6 so nothing is written twice.
The resolver returns zero or more than one matching list. The scenario emails the admin with the details and stops. No records are changed until a human resolves it. Flagging a person beats guessing the wrong segment.
The Manual enrollment - skip automation checkbox is set, so the wait and booking check are skipped, but steps 2 through 6 still run to keep the records current.
The routing reads the level and delivery from the purchased item and covers every course you sell. Five courses run both in-person and remote (ten combinations); Growth Strategies and the AI Workshop are in-person only (two more), for twelve in total.
| Course | Level | Family | Sessions | Delivery |
|---|---|---|---|---|
| MS Study Skills and Strategies Course | MS | SSS | 5 | In-Person, Remote |
| HS Study Skills and Strategies Course | HS | SSS | 5 | In-Person, Remote |
| College Study Skills and Strategies Course | College | SSS | 5 | In-Person, Remote |
| MS Writing: Start to Finish | MS | Writing | 5 | In-Person, Remote |
| HS Writing: Start to Finish | HS | Writing | 5 | In-Person, Remote |
| Growth Strategies Study Skills Course (GM / ES, grades 4-5) | ES | SSS | 5 | In-Person only |
| AI to Improve Executive Functions Workshop | AIW | Workshop | 1 | In-Person only |
The AI Workshop is a single-session course, which is why a zero-booking result there is the expected path rather than an error. Only MS and HS Study Skills, in-person, in the summer, page the VA.
The importable Make blueprint and a full module by module runbook. The blueprint's MindBody steps use generic HTTP and a custom webhook so it imports into any Make account without the StartIntegrate connector installed. Each connector boundary is labelled where the native action swaps in once it is present.