WhatsApp Appointment Cancellation Flow Template

A one-screen cancellation form that records why the client is cancelling, lets them add a comment and, most importantly, asks whether they want another slot offered. It turns a lost booking into a rebooking conversation instead of a silent gap in your diary.

1 screen 3 fields returned Flow JSON 7.2 Appointment booking Clinics, Dental, Salons, Spas, Studios, Tutors

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

appointment-cancellation.json Open in Flow Builder
{
  "version": "7.2",
  "screens": [
    {
      "id": "CANCEL_APPOINTMENT",
      "title": "Cancel appointment",
      "terminal": true,
      "data": {},
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "Form",
            "name": "form_cancel_appointment",
            "children": [
              {
                "type": "TextHeading",
                "text": "Cancel your appointment"
              },
              {
                "type": "TextBody",
                "text": "Please let us know why you are cancelling. Cancellations with less than 24 hours notice may be charged under our booking policy."
              },
              {
                "type": "RadioButtonsGroup",
                "name": "cancel_reason",
                "label": "Reason for cancelling",
                "data-source": [
                  {
                    "id": "schedule_conflict",
                    "title": "Schedule conflict"
                  },
                  {
                    "id": "feeling_unwell",
                    "title": "Feeling unwell"
                  },
                  {
                    "id": "no_longer_needed",
                    "title": "No longer needed"
                  },
                  {
                    "id": "cost",
                    "title": "Cost"
                  },
                  {
                    "id": "travel_distance",
                    "title": "Travel or distance"
                  },
                  {
                    "id": "booked_elsewhere",
                    "title": "Booked elsewhere"
                  },
                  {
                    "id": "unhappy_last_visit",
                    "title": "Unhappy with last visit"
                  },
                  {
                    "id": "other_reason",
                    "title": "Something else"
                  }
                ],
                "required": true
              },
              {
                "type": "RadioButtonsGroup",
                "name": "rebook_preference",
                "label": "Book another time?",
                "data-source": [
                  {
                    "id": "offer_slot",
                    "title": "Yes, offer me another slot",
                    "description": "We will message you with the next available times"
                  },
                  {
                    "id": "call_me",
                    "title": "Call me to arrange",
                    "description": "A team member will phone you"
                  },
                  {
                    "id": "no_thanks",
                    "title": "No thanks, not right now"
                  }
                ],
                "required": true
              },
              {
                "type": "TextArea",
                "name": "cancel_comment",
                "label": "Comments",
                "helper-text": "Anything you would like us to know (optional)"
              },
              {
                "type": "Footer",
                "label": "Confirm cancellation",
                "on-click-action": {
                  "name": "complete",
                  "payload": {
                    "cancel_reason": "${form.cancel_reason}",
                    "rebook_preference": "${form.rebook_preference}",
                    "cancel_comment": "${form.cancel_comment}"
                  }
                }
              }
            ]
          }
        ]
      }
    }
  ]
}

Raw JSON for scripts: curl -s https://whautomate.com/whatsapp-flow-templates/appointment-cancellation.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 appointment cancellation flow

A plain "cancel" reply tells you nothing: not why the client cancelled, and not whether they still want the service. This flow collects both in a few taps. The reason list gives you data you can actually report on, and the rebooking question tells your team who to call back and who to leave alone.

The rebooking question is the part that pays for itself. Clients who cancel because of a work clash or illness usually still want the appointment; they just need a different day. Asking "shall we offer you another slot?" at the moment of cancelling catches them while the intent is still there, before they forget or book somewhere else.

Everything sits on one screen because cancellation should never feel like a maze. The only required answers are the reason and the rebooking choice. The comment is optional and exists for the cases a fixed list cannot cover, such as a complaint about the last visit that someone senior should read.

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
cancel_reason
schedule_conflict, feeling_unwell, no_longer_needed, cost, travel_distance, booked_elsewhere, unhappy_last_visit, other_reason
RadioButtonsGroup CANCEL_APPOINTMENT Yes item id "schedule_conflict"
rebook_preference
offer_slot, call_me, no_thanks
RadioButtonsGroup CANCEL_APPOINTMENT Yes item id "offer_slot"
cancel_comment TextArea CANCEL_APPOINTMENT No string "Weekday mornings are hard for me now, evenings would be better."

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 Appointment Cancellation 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",
  "cancel_reason": "schedule_conflict",
  "rebook_preference": "offer_slot",
  "cancel_comment": "Weekday mornings are hard for me now, evenings would be better."
}
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\",\"cancel_reason\":\"schedule_conflict\",\"rebook_preference\":\"offer_slot\",\"cancel_comment\":\"Weekday mornings are hard for me now, evenings would be better.\"}"
                  }
                }
              }
            ]
          }
        }
      ]
    }
  ]
}

Deploy with the WhatsApp Cloud API

Prefer code over WhatsApp Manager? Save the template as appointment-cancellation.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": "appointment_cancellation", "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-appointment-cancellation.json
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "14155550123",
  "type": "interactive",
  "interactive": {
    "type": "flow",
    "header": {
      "type": "text",
      "text": "Cancel your appointment"
    },
    "body": {
      "text": "Sorry you cannot make it. Tap below to cancel, and let us know if you would like us to offer you another time."
    },
    "footer": {
      "text": "Cancelling early frees the slot for someone else"
    },
    "action": {
      "name": "flow",
      "parameters": {
        "flow_message_version": "3",
        "flow_token": "bk_8f2c41",
        "flow_id": "YOUR_FLOW_ID",
        "flow_cta": "Cancel appointment",
        "flow_action": "navigate",
        "flow_action_payload": {
          "screen": "CANCEL_APPOINTMENT"
        }
      }
    }
  }
}
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-appointment-cancellation.json

When to send it

Reply to a reminder

Add a "Need to cancel?" Flow button to your appointment reminder template, so the client cancels in a structured way instead of replying "can't come" at 7am.

Keyword "cancel"

Route inbound messages that contain "cancel" or "can't make it" to a chatbot step that sends this flow, with the booking id in the flow_token.

Unconfirmed bookings

Send it the day before to clients who have not confirmed. An easy, polite way to cancel frees slots that would otherwise become no-shows.

Course or package sessions

For tutors and studios selling blocks of sessions, send it when a client wants to skip a session, and use the rebook answer to schedule the make-up lesson.

How to customise this template

  • Keep the reason list short and mutually exclusive. Six to eight options is plenty; if "Something else" starts getting more than 10% of answers, read the comments and promote the common theme to its own id.
  • Reword the rebook options to match what your team can actually do. If you cannot call clients back, drop call_me and keep offer_slot and no_thanks.
  • State your cancellation policy in the TextBody. If late cancellations are charged, say the notice period plainly so the client sees it before they submit.
  • If you run a waitlist, use cancel_reason plus the original booking time to trigger an offer of the freed slot to the next person on your list.

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

  • Submitting the flow should not be the only record of the cancellation. Send a short confirmation message ("Your 3pm on Tuesday is cancelled") so the client has proof and does not turn up anyway.
  • Do not make the comment field required. Clients who are cancelling have low patience, and a mandatory free-text box is the fastest way to get them to abandon the form and just not show up.
  • The flow does not know the booking unless you tell it. Put the appointment id in flow_token when you send; the form has no booking picker because a static flow cannot list the client's live appointments.
  • Rebook answers go stale fast. If the client picked offer_slot, reply with options the same day, ideally within the hour, or the intent disappears.

Let clients manage bookings themselves

Whautomate has a built-in customer portal flow. Clients see their upcoming appointments, classes, events or orders and can cancel within your cancellation window, without messaging your team. It is created and published for you and runs on live data.

  • Upcoming bookings pulled live for the client
  • Cancellation window enforced automatically
  • Nothing to host or maintain

7-day free trial, no credit card required.

Frequently asked questions

Not in a static flow. Listing a client's real bookings needs a data_exchange endpoint that returns them when the flow opens. This template assumes you send it about one booking and identify it with the flow_token.
An nfm_reply message whose response_json holds the flow_token, cancel_reason (an item id such as schedule_conflict), rebook_preference (offer_slot, call_me or no_thanks) and cancel_comment as a string, or empty if skipped.
A keyword reply is quicker to build but gives you no reason and no rebooking intent. The flow adds about ten seconds for the client and gives you both, which is worth it for any business that cares about utilisation.
Whautomate's built-in customer portal flow lists each client's upcoming appointments and lets them cancel within your cancellation window, with no staff step. It is created and published in your account and runs on live data.

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.