Build documentation · sample runbook

CourseSync build documentation

A module by module runbook for the MindBody purchase to enrollment scenario: what each module does, the field mappings, and how each step handles the things that go wrong. This is the sample of what full documentation with every build looks like.

← back to the walkthrough

Scope and honesty

This documents the blueprint built for the specification posted publicly on Make's Hire a Pro board. It runs on invented sample data. No prior StartIntegrate or MindBody client build is claimed. The MindBody steps are written with generic HTTP so the blueprint imports into any Make account without the connector installed; each connector boundary notes where the native StartIntegrate module swaps in.

Contents

1. Connections and prerequisites

ConnectionUsed byNotes
MindBody APISteps trigger, 1API key or OAuth 2.0 with a staff user token. The webhook subscription is a separate MindBody Webhooks API setup. Three request headers on every call: Api-Key, SiteId, Authorization: Bearer.
HubSpotSteps 2, 3, 6Private app token. Scopes needed: crm.objects.contacts.write, crm.lists.write, and marketing-email for the Single-Send API. Single-Send requires Marketing Hub Enterprise.
Google SheetsStep 4Access to the target spreadsheet with an Enrollments tab.
Gmail or emailStep 5Any send-capable connection. Swap for Slack or a Trainual task if the VA prefers.

Values to supply before the scenario runs: the MindBody SiteId, the HubSpot manual list id, the Google spreadsheet id, the HubSpot confirmation template id, and the VA recipient.

2. Trigger setup and signature verification

The StartIntegrate connector has no purchase trigger, so the scenario is fired by a MindBody webhook, not a connector poll.

  1. In the MindBody Webhooks API, create a subscription for the event clientSale.created. Point its delivery URL at this scenario's custom webhook address.
  2. MindBody returns a messageSignatureKey for the subscription. Store it in the scenario.
  3. On every delivery, compute HMAC-SHA256 over the raw request body using that key and compare, as sha256=<hash>, against the X-Mindbody-Signature header. Reject the bundle if it does not match.

The delivered envelope is { messageId, eventId, eventSchemaVersion, eventInstanceOriginationDateTime, eventData }. eventSchemaVersion is always 1. eventData carries siteId, clientId, clientUniqueId, saleId, and the purchased items.

3. Module by module reference

IDModulePurposeKey mappings
1gateway:CustomWebHook Receive clientSale.created from MindBody. parameters left empty; configure the webhook and signature after import
2http:ActionSendData GET the client's existing visits so the fill step knows what she already has. GET /public/v6/client/clientvisits?clientId={{1.eventData.clientId}}; response at {{2.data.Visits}}
3builtin:BasicRouter Fan out to four independent routes: fill sessions, update records, alert VA, confirm. no mapper; routes are not mutually exclusive
4builtin:BasicFeeder Iterate the course's five required session ClassIds. array of ClassIds; in production resolved from the course via GET /class/classes
5http:ActionSendData POST add the student to a session, filtered to missing sessions only. POST /public/v6/class/addclienttoclass; body ClientId, ClassId {{4.value}}; filter: existing set notcontain {{4.value}}
6hubspotcrm:createOrUpdateAContact Write the coursesync_ enrollment properties. match on email; properties are coursesync_ only
7hubspotcrm:makeApiCall Add the contact to the correct manual list. PUT /crm/v3/lists/{listId}/memberships/add; body ["{{6.id}}"]
8google-sheets:addRow Append one audit row per purchase. Enrollments tab; timestamp, student, course, sessions added, sale id
9google-email:ActionSendEmail Conditionally alert the VA for a mid course join. filter: length(existing visits) > 0
10hubspotcrm:makeApiCall Send the confirmation from a HubSpot template. POST /marketing/v4/email/single-send; emailId, message.to, customProperties

4. The two parts that carry the build

The purchase trigger

The connector's only triggers are Watch New Clients and Watch Updated Clients. Neither fires on a sale. The correct pattern is a MindBody Webhooks API subscription to clientSale.created delivered to the custom webhook in module 1. If webhooks are not available on the account, the fallback is a scheduled poll of the Sale endpoint via a Make an API Call, storing the last seen sale id to avoid reprocessing.

The missing only enrollment check

The connector can add a client to a class but cannot return a client's existing visits. Module 2 fills that gap with GET /client/clientvisits. Module 5 then adds a session only when the existing set does not contain that session's ClassId. The filter is one condition: join(existing ClassIds) notcontain current ClassId. This is what makes re-runs and partial enrollments safe. A student already in sessions 1 and 2 is added to 3, 4, and 5, and never re-added to 1 or 2.

5. Appiant coexistence

Your existing Appiant integration keeps MindBody and HubSpot contact records in sync. This scenario must not fight it. Two rules enforce that:

The result is a clean separation. Appiant owns identity. This scenario owns the enrollment state, and the two never write the same field.

6. Error handling and edge cases

SituationHandling
Signature does not matchReject the bundle before any downstream module runs. A mismatch means the payload is not from MindBody.
Sale is not a course purchaseFilter the router's fill route on the item type or course id so unrelated sales do not trigger enrollment.
clientSale.created has no emailResolve the email first with GET /client/clients on the clientId before the HubSpot steps. The sale payload carries the client id reliably; email is not guaranteed.
Session is full or waitlistedaddclienttoclass accepts a Waitlist flag. Decide per course whether to waitlist or skip, and surface the outcome to the audit row.
Student already in every sessionThe missing only filter blocks all adds. The rest of the scenario still records and confirms. No duplicate enrollments are created.
Re-delivery of the same webhookMindBody may retry. Dedupe on messageId, or rely on the missing only filter, which makes a repeat run a no op for enrollments.
HubSpot list add returns a not foundConfirm the list id is the ILS id of a manual or snapshot list. The Lists v3 add endpoint requires that list type.
Transient API failureSet the scenario's error handling to retry the HTTP and HubSpot modules. Route unrecoverable errors to a data store or a notification so nothing fails silently.

7. Importing and what to swap in

  1. In Make, create a new scenario and import coursesync.blueprint.json.
  2. Attach connections: MindBody credentials on the HTTP modules, HubSpot, Google Sheets, and the send connection.
  3. Supply the values: SiteId, HubSpot list id, spreadsheet id, confirmation template id, VA recipient, and the course's session ClassIds.
  4. Configure the custom webhook and the MindBody clientSale.created subscription, then store the signature key.
  5. Optional: once the StartIntegrate connector is installed in the account, swap the two MindBody HTTP modules for the native Add a Client to a Class action. Every connector boundary in the blueprint is labelled where this swap applies. The enrollment check stays as a Make an API Call because the connector has no get visits action.
  6. Run once with a test sale and confirm: two sessions skipped, three added, the HubSpot property set, the list membership added, the sheet row appended, the VA alerted, and the confirmation sent.