WhatsApp Salon Service Menu Flow Template

A two-screen salon booking request built around a real service menu. Clients tick one or more services, each showing its duration and price, pick a stylist and a time window, then leave their details and any notes about hair, skin or nails.

2 screens 8 fields returned Flow JSON 7.2 Appointment booking Hair salons, Barbers, Nail studios, Beauty salons, Spas

Use Try it to fill the flow and see the exact response_json it returns.

salon-service-menu.json Open in Flow Builder
{
  "version": "7.2",
  "screens": [
    {
      "id": "SERVICE_MENU",
      "title": "Service menu",
      "data": {},
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "Form",
            "name": "form_service_menu",
            "children": [
              {
                "type": "TextHeading",
                "text": "Choose your services"
              },
              {
                "type": "TextBody",
                "text": "Pick up to four services for one visit. Prices are a starting guide and we confirm the final price before your appointment."
              },
              {
                "type": "CheckboxGroup",
                "name": "services",
                "label": "Services",
                "data-source": [
                  {
                    "id": "cut_blowdry",
                    "title": "Cut & blow-dry",
                    "description": "60 min",
                    "metadata": "$55"
                  },
                  {
                    "id": "mens_cut",
                    "title": "Men's cut",
                    "description": "30 min",
                    "metadata": "$30"
                  },
                  {
                    "id": "blowdry_only",
                    "title": "Blow-dry & style",
                    "description": "45 min",
                    "metadata": "$35"
                  },
                  {
                    "id": "root_colour",
                    "title": "Root colour",
                    "description": "90 min, includes blow-dry",
                    "metadata": "$75"
                  },
                  {
                    "id": "balayage",
                    "title": "Balayage",
                    "description": "3 hrs, consultation on the day",
                    "metadata": "from $160"
                  },
                  {
                    "id": "gloss_toner",
                    "title": "Gloss or toner",
                    "description": "30 min, add-on to any colour or cut",
                    "metadata": "$25"
                  },
                  {
                    "id": "keratin",
                    "title": "Keratin smoothing",
                    "description": "2.5 hrs, longer for thick hair",
                    "metadata": "from $180"
                  },
                  {
                    "id": "gel_manicure",
                    "title": "Gel manicure",
                    "description": "45 min",
                    "metadata": "$40"
                  },
                  {
                    "id": "brow_shape_tint",
                    "title": "Brow shape & tint",
                    "description": "30 min, patch test needed",
                    "metadata": "$28"
                  }
                ],
                "required": true,
                "min-selected-items": 1,
                "max-selected-items": 4
              },
              {
                "type": "Dropdown",
                "name": "stylist",
                "label": "Stylist",
                "data-source": [
                  {
                    "id": "any_stylist",
                    "title": "First available"
                  },
                  {
                    "id": "stylist_amira",
                    "title": "Amira (senior stylist)"
                  },
                  {
                    "id": "stylist_leo",
                    "title": "Leo (colour specialist)"
                  },
                  {
                    "id": "stylist_hana",
                    "title": "Hana (stylist)"
                  },
                  {
                    "id": "stylist_nail_tech",
                    "title": "Rosa (nails and brows)"
                  }
                ]
              },
              {
                "type": "DatePicker",
                "name": "salon_visit_date",
                "label": "Preferred date",
                "required": true
              },
              {
                "type": "RadioButtonsGroup",
                "name": "salon_time_window",
                "label": "Preferred time",
                "data-source": [
                  {
                    "id": "morning",
                    "title": "Morning (9am - 12pm)"
                  },
                  {
                    "id": "midday",
                    "title": "Midday (12pm - 3pm)"
                  },
                  {
                    "id": "afternoon",
                    "title": "Afternoon (3pm - 6pm)"
                  },
                  {
                    "id": "late_evening",
                    "title": "Late night (6pm - 9pm)",
                    "description": "Thursdays and Fridays only"
                  }
                ],
                "required": true
              },
              {
                "type": "Footer",
                "label": "Continue",
                "on-click-action": {
                  "name": "navigate",
                  "next": {
                    "type": "screen",
                    "name": "CLIENT_DETAILS"
                  },
                  "payload": {}
                }
              }
            ]
          }
        ]
      }
    },
    {
      "id": "CLIENT_DETAILS",
      "title": "Your details",
      "terminal": true,
      "data": {},
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "Form",
            "name": "form_client_details",
            "children": [
              {
                "type": "TextSubheading",
                "text": "Who is the booking for?"
              },
              {
                "type": "TextInput",
                "name": "client_name",
                "label": "Name",
                "input-type": "text",
                "required": true
              },
              {
                "type": "TextInput",
                "name": "client_email",
                "label": "Email",
                "input-type": "email",
                "helper-text": "For your booking confirmation"
              },
              {
                "type": "RadioButtonsGroup",
                "name": "first_visit",
                "label": "First time with us?",
                "data-source": [
                  {
                    "id": "first_visit_yes",
                    "title": "Yes, first visit",
                    "description": "Colour and tint services need a patch test 48 hours before"
                  },
                  {
                    "id": "first_visit_no",
                    "title": "No, I have been before"
                  }
                ],
                "required": true
              },
              {
                "type": "TextArea",
                "name": "salon_notes",
                "label": "Notes",
                "helper-text": "Hair length, inspiration, sensitivities"
              },
              {
                "type": "TextCaption",
                "text": "We will reply to confirm your exact time and total price."
              },
              {
                "type": "Footer",
                "label": "Send booking request",
                "on-click-action": {
                  "name": "complete",
                  "payload": {
                    "services": "${screen.SERVICE_MENU.form.services}",
                    "stylist": "${screen.SERVICE_MENU.form.stylist}",
                    "salon_visit_date": "${screen.SERVICE_MENU.form.salon_visit_date}",
                    "salon_time_window": "${screen.SERVICE_MENU.form.salon_time_window}",
                    "client_name": "${form.client_name}",
                    "client_email": "${form.client_email}",
                    "first_visit": "${form.first_visit}",
                    "salon_notes": "${form.salon_notes}"
                  }
                }
              }
            ]
          }
        ]
      }
    }
  ]
}

Raw JSON for scripts: curl -s https://whautomate.com/whatsapp-flow-templates/salon-service-menu.json

Import in 60 seconds
  1. Copy the JSON above (or edit it first in the Flow Builder).
  2. In WhatsApp Manager, open Account tools > Flows, create a flow and choose Appointment booking as the category.
  3. Paste into the JSON editor, check the preview, then Publish.
  4. Send it with the Flow ID, as an interactive message or through a template's Flow button.

Not technical? Skip the JSON and send it from Whautomate with a drag-and-drop editor.

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.

KeyComponentScreenRequiredReturnsExample
services
cut_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"]
stylist
any_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_window
morning, 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_visit
first_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.

No developer needed

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.

1

Connect your number

Log in with Facebook and connect your WhatsApp number in a few minutes. No API keys or servers to set up.

2

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.

3

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.

4

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.

7-day free trial, no credit card required.

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.

response_json (parsed)
{
  "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."
}
POST your-webhook (full event)
{
  "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

bash
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

bash
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

bash
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.

send-salon-service-menu.json
{
  "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"
        }
      }
    }
  }
}
bash
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.json

When 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.

Frequently asked questions

Yes. services is a CheckboxGroup with min-selected-items set to 1 and max-selected-items set to 4. The webhook returns an array such as ["cut_blowdry", "gloss_toner"].
In the item metadata, which WhatsApp renders on the right-hand side of each option. It is capped at 20 characters, so keep it to a figure or a short "from" price.
Not as a static flow. Filtering stylists by availability needs a data_exchange endpoint that returns options when the date changes. This template collects a preference and your team confirms the booking.
The sender's phone number arrives with the nfm_reply message, and you can set flow_token to your own client or campaign id when sending. Use either to match the request to the client record.

The Complete Omnichannel Customer Engagement Platform

Go beyond free tools. Automate conversations, build AI chatbots, send broadcast campaigns, book appointments, sell products, and manage every messaging channel from one powerful platform. Trusted by thousands of businesses worldwide.

  • WhatsApp, Instagram, Messenger, Telegram & Live Chat
  • AI chatbots & no-code automation
  • Broadcast campaigns & analytics
  • Appointment & class booking
  • E-commerce, Shopify & WooCommerce integration
  • CRM, invoicing & payment collection

No credit card required. Free 7-day trial. Visit our pricing page for plans.