About this salon service menu flow
Salon clients rarely book one thing. A cut becomes a cut and blow-dry, a colour needs a toner, a manicure turns into mani-pedi. A single-choice service list forces them to pick one and explain the rest in a message. This template uses a CheckboxGroup so clients can combine services, and your team sees the whole visit in one answer.
Each menu item carries its duration in the description and its price in the metadata, which WhatsApp shows on the right of the row. Clients can add up the time and cost before they submit, which cuts the "how much is that?" follow-ups and stops people booking a 30-minute gap for a three-hour colour.
Screen two is deliberately short: name, email, a first-visit question and notes. The first-visit answer matters for salons because new colour clients often need a patch test 48 hours before, and knowing up front lets you book it without a second conversation.
Fields this flow returns
When the customer taps the final button, the complete action sends these keys back in response_json. Fields from earlier screens are pulled in with global references (${screen.SCREEN_ID.form.field}), so nothing is lost between screens.
| Key | Component | Screen | Required | Returns | Example |
|---|---|---|---|---|---|
servicescut_blowdry, mens_cut, blowdry_only, root_colour, balayage, gloss_toner, keratin, gel_manicure, brow_shape_tint |
CheckboxGroup | SERVICE_MENU | Yes | array of ids | ["cut_blowdry","gloss_toner"] |
stylistany_stylist, stylist_amira, stylist_leo, stylist_hana, stylist_nail_tech |
Dropdown | SERVICE_MENU | No | item id | "stylist_amira" |
salon_visit_date |
DatePicker | SERVICE_MENU | Yes | YYYY-MM-DD | "2026-11-06" |
salon_time_windowmorning, midday, afternoon, late_evening |
RadioButtonsGroup | SERVICE_MENU | Yes | item id | "midday" |
client_name |
TextInput | CLIENT_DETAILS | Yes | string | "Chloe Bennett" |
client_email |
TextInput (email) | CLIENT_DETAILS | No | string | "[email protected]" |
first_visitfirst_visit_yes, first_visit_no |
RadioButtonsGroup | CLIENT_DETAILS | Yes | item id | "first_visit_yes" |
salon_notes |
TextArea | CLIENT_DETAILS | No | string | "Shoulder-length, fine hair. Want to keep the length but add layers." |
Optional fields the customer leaves empty may be missing from response_json or arrive empty. Treat every optional key as nullable in your handler.
Send the Salon Service Menu flow without touching code
You do not need to be technical to use WhatsApp Flows. Connect your WhatsApp number, set the flow up in our drag-and-drop editor and send it to customers in a few clicks. No JSON, no API calls, no WhatsApp Manager.
Connect your number
Log in with Facebook and connect your WhatsApp number in a few minutes. No API keys or servers to set up.
Set up the flow
Start from a ready-made form or import this one, then drag fields in, change the wording and try it on a live phone preview. Click Publish when it looks right.
Send it anywhere
Send it from any chat in the Team Inbox, on web or mobile, send it automatically from an automation, or broadcast it to a list.
Get the answers
Every answer is saved on the customer's profile and chat, and your team can be notified the moment a form comes in.
Sample webhook payload (nfm_reply)
This is what your webhook receives when a customer submits the flow. response_json is a JSON string: parse it, then match flow_token to the record you created when you sent the message. The customer's WhatsApp number is in messages[0].from.
{
"flow_token": "bk_8f2c41",
"services": [
"cut_blowdry",
"gloss_toner"
],
"stylist": "stylist_amira",
"salon_visit_date": "2026-11-06",
"salon_time_window": "midday",
"client_name": "Chloe Bennett",
"client_email": "[email protected]",
"first_visit": "first_visit_yes",
"salon_notes": "Shoulder-length, fine hair. Want to keep the length but add layers."
}
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "WHATSAPP_BUSINESS_ACCOUNT_ID",
"changes": [
{
"field": "messages",
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "15550001234",
"phone_number_id": "PHONE_NUMBER_ID"
},
"contacts": [
{
"profile": {
"name": "Alex Morgan"
},
"wa_id": "14155550123"
}
],
"messages": [
{
"context": {
"from": "15550001234",
"id": "wamid.SENT_FLOW_MESSAGE_ID"
},
"from": "14155550123",
"id": "wamid.INCOMING_MESSAGE_ID",
"timestamp": "1760000000",
"type": "interactive",
"interactive": {
"type": "nfm_reply",
"nfm_reply": {
"name": "flow",
"body": "Sent",
"response_json": "{\"flow_token\":\"bk_8f2c41\",\"services\":[\"cut_blowdry\",\"gloss_toner\"],\"stylist\":\"stylist_amira\",\"salon_visit_date\":\"2026-11-06\",\"salon_time_window\":\"midday\",\"client_name\":\"Chloe Bennett\",\"client_email\":\"[email protected]\",\"first_visit\":\"first_visit_yes\",\"salon_notes\":\"Shoulder-length, fine hair. Want to keep the length but add layers.\"}"
}
}
}
]
}
}
]
}
]
}
Deploy with the WhatsApp Cloud API
Prefer code over WhatsApp Manager? Save the template as salon-service-menu.json and run these calls with a system user token that has whatsapp_business_management and whatsapp_business_messaging permissions.
1. Create the flow
curl -X POST 'https://graph.facebook.com/v23.0/{WABA_ID}/flows' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{"name": "salon_service_menu", "categories": ["APPOINTMENT_BOOKING"]}'
# => {"id": "{FLOW_ID}"}2. Upload the Flow JSON
curl -X POST 'https://graph.facebook.com/v23.0/{FLOW_ID}/assets' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F '[email protected];type=application/json' \
-F 'name=flow.json' \
-F 'asset_type=FLOW_JSON'
# => {"success": true, "validation_errors": []}3. Publish it
curl -X POST 'https://graph.facebook.com/v23.0/{FLOW_ID}/publish' \
-H 'Authorization: Bearer {ACCESS_TOKEN}'Publishing is permanent: a published flow cannot be edited. To change it later, create a new flow (or clone it with clone_flow_id) and publish the new version.
4. Send it to a customer
Inside the 24-hour customer service window, send an interactive flow message. Outside it, create a message template with a Flow button that points to this flow, and send the template instead.
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "14155550123",
"type": "interactive",
"interactive": {
"type": "flow",
"header": {
"type": "text",
"text": "Our service menu"
},
"body": {
"text": "See our prices, choose your services and pick a stylist. We will confirm your appointment time here on WhatsApp."
},
"footer": {
"text": "Prices may vary by hair length"
},
"action": {
"name": "flow",
"parameters": {
"flow_message_version": "3",
"flow_token": "bk_8f2c41",
"flow_id": "YOUR_FLOW_ID",
"flow_cta": "View menu and book",
"flow_action": "navigate",
"flow_action_payload": {
"screen": "SERVICE_MENU"
}
}
}
}
}curl -X POST 'https://graph.facebook.com/v23.0/{PHONE_NUMBER_ID}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-H 'Content-Type: application/json' \
-d @send-salon-service-menu.jsonWhen to send it
Price enquiries
When someone asks "how much for highlights?", reply with this flow. It answers the price question and moves straight to booking in the same tap.
Instagram and TikTok traffic
Clients arriving from a reel of a balayage often want to know the menu first. Send the flow as the first reply from your click-to-WhatsApp ads.
Seasonal offers
Before holidays or wedding season, broadcast a Flow-button template that opens the menu, so clients can book party hair or nails in one go.
Rebooking after 6 weeks
Colour and cut clients return on a cycle. Send the menu five to eight weeks after their last visit so they rebook before the roots show.
How to customise this template
- Replace the services with your own menu, up to 20 items per CheckboxGroup. If you have more, split them into two groups, for example hair on one screen and nails or beauty on another.
- Metadata is limited to 20 characters, so write prices like "$45" or "from $120". Put nuance such as "long hair +$20" in the description instead.
- Adjust max-selected-items to stop unrealistic combinations. Four services is a sensible ceiling for a single visit; raise it for spa days or bridal packages.
- List stylists by first name, or by level (senior stylist, stylist, graduate) if your prices differ by level. The dropdown keeps the screen tidy even with a large team.
Open this template in the Flow Builder to make these changes visually. The builder keeps field names unique and regenerates the completion payload for you.
Common mistakes to avoid
- Do not show a total price. A static flow cannot add up the selected items, and a wrong total is worse than none. Let the client see each price and confirm the final figure in your reply.
- CheckboxGroup returns an array of ids, and you should not treat its order as meaningful. If service sequence matters (colour before cut, cut before blow-dry), sort the ids in your handler using your own menu order.
- Durations in descriptions are the client's only guide to the time needed. Keep them accurate, or a client will pick a time window that cannot fit their combination.
- Remember patch tests. If first_visit is yes and the services include colour or lash tints, reply with a patch test slot before confirming the main appointment.
Need live availability instead of a "preferred time"?
A static flow can only collect a requested time, so your team still has to confirm it by hand. Whautomate ships a built-in appointment booking flow that reads your real services, staff and open slots, books the appointment directly and sends the confirmation. It is created and published in your WhatsApp account from an automation template, and it runs on an encrypted endpoint Whautomate hosts. There is no endpoint code for you to write.
- Live services, staff and time slots from your calendar
- Books directly, with no manual confirmation step
- Multi-location version picks the branch first
7-day free trial, no credit card required.