Skip to content

SMS and WhatsApp booking confirmations in Laravel, without code ​

A client books a haircut for next Tuesday. The confirmation email lands in a folder they never open, Tuesday comes, and the chair stays empty. A customer orders at ten in the evening and wonders until morning whether the order went through. Both would have read a text within a minute: a text is what cuts no-shows, and what tells a customer the shop heard them.

Sending one from Laravel is a few lines against Twilio's API. Sending them from a site is the rest: which events deserve a text and to whom, the phone a client typed with no country code, the delivery receipt that says it arrived, the law that says a STOP must be obeyed, the template Meta must approve before a business may write first on WhatsApp, a log the front desk can read, and what to do when the provider refuses ten texts in a row because the balance ran out. kitloom/text-messages is that work done once, for the bookings, the shop and the owner's own notifications.

Ask the agent ​

With kitloom/ai connected, an agent whose user manages the texts answers from the log and acts on it:

  • "Did Anna get her reminder for Tuesday?" (text_messages_list)
  • "Why did yesterday's confirmations fail?" — the provider's own words are on each row.
  • "Mrs. Lee asked on the phone not to be texted any more." (text_messages_opt_out)
  • "Send a test to my phone, I just changed the number." (text_messages_send_test)

The Twilio or Vonage keys stay on the Settings page, encrypted, where a person pastes them; an agent never sees them and cannot change where the texts come from.

What is texted ​

Each text goes to the phone the person typed on the booking form or at the checkout, beside the email, in the language they booked or ordered in. Nothing replaces the emails: they go on as before, the text is the one that gets read.

FromTextTo
Bookingsreceived, confirmed, a reminder the hours before the visit (as Bookings → Settings say), declined, cancelledthe client
Bookingsa new booking, with a link to confirm it; a cancellationthe staff member's phone, from their card in Bookings → Staff
Shoporder received (when the shop's own "new order" email goes), completed, cancelled, refunded with the amountthe billing phone
Notificationsthe owner's news — a new order, a failed backup — on a channel of type SMS or WhatsApp in Notifications → Channelsyour phone

Each group is a switch under What is texted, on from the start. The words are the module's, in the site's language: Marginalia: your Haircut on Tue 3 Nov 10:00 is confirmed. Manage: https://…/booking/7KQ2MN/…. The links are short ones that open the same pages as the emails' buttons.

Not texted, on purpose: the "time to book again" email, comments, form messages, low stock. Those are marketing or the owner's business, and a marketing text needs a consent of its own.

Set up in the admin ​

Text Messages → Settings, in a few minutes:

  1. The provider. Twilio, most used in North America, or Vonage, strong in Europe; both are set up the same way. On Twilio's console front page: the Account SID and the Auth token; under Phone Numbers, the number the texts come from. A trial account texts only the numbers you verified.
  2. The keys. The Account SID, the auth token, the number as the SMS sender in international form. The token is kept encrypted with the application key and never shown again: an empty field later keeps the one saved. Where the country allows it, a name of up to eleven letters can send instead of a number; Canada and the US do not.
  3. The webhooks. The page shows two addresses. The Status URL is how Twilio or Vonage tell the site a text was delivered; the Inbound URL, pasted under A message comes in on the number, is how the site hears STOP, START and the replies. Every call is signed by the provider and the site answers only the signed ones.
  4. Country, two letters, says what a phone typed without its plus code means. Without it, only numbers with a code are texted: a guessed prefix would text a stranger.
  5. Send a test to a phone of yours. Twilio takes it, the notice says it is on its way, and Messages shows whether it was delivered.

Text Messages → Messages is the log: every text the site sent or received, newest first — when, sent or received, the phone, what it was about, SMS or WhatsApp, and its status. Delivered is the provider's receipt. Failed carries the provider's words, so a landline typed as a mobile is found at a glance and the client asked for another number; the email reminder went out all the same. Opening a text shows the words as sent, how many SMS parts they took, the provider's id to find it in Twilio, and the booking it was about.

STOP, and the law ​

What the site texts is the person's own transaction — the booking they made, the order they placed — which Canada's anti-spam law and the US TCPA treat as consented to by the transaction itself. Still, a person who answers STOP (or UNSUBSCRIBE, CANCEL, ARRET…) is texted nothing more on that channel: each text to them is logged Said STOP instead, until they answer START. A client who asks in person goes on the list by hand, Stop texting a number in Messages; the same button takes them off. The emails keep going either way.

WhatsApp, kind by kind ​

A business may write first on WhatsApp only with a template Meta approved, with numbered blanks the site fills. So WhatsApp works kind by kind: switch Send WhatsApp on, name the WhatsApp Business number, and paste an approved template's id next to each kind under WhatsApp templates — a kind left empty goes by SMS. The guide lists the blanks each kind fills, in order, so the templates are written right the first time; Meta's approval takes from a day to a few.

When the provider says no ​

A text is sent from the queue: a provider that is busy gets it again, three tries; one that refuses it gets it no more. Ten refusals in a row — a wrong key, an empty balance — turn sending off: bookings and orders go by email only, the administrator gets an email, and Site Health says so. Fix it, press Send a test, and a text that gets through turns sending back on.

The log keeps the words for ninety days (Settings says how long); the rows stay for the counts. Export and Erase Personal Data cover the texts of a person's phone; a STOP is kept, since forgetting it would let the site text them again.

For a Laravel developer ​

Bookings, the shop and the notifications never name this module. They text through a contract in the core, Kitloom\WpSchema\Messaging\TextMessenger, and Laravel's own notifications: a notification adds TextChannel::class beside mail and answers toText() with the words. A module of your own does the same:

php
public function via(object $notifiable): array
{
    return array_filter(['mail', $this->texts->channels('review.reply') ? TextChannel::class : null]);
}

public function toText(object $notifiable): ?OutgoingText
{
    return new OutgoingText(__('Your review got a reply: :url', ['url' => $this->url]), kind: 'review.reply');
}

Without the module nothing is texted and nothing breaks; channels($kind) says whether the owner texts that kind at all. The module reaches Twilio and Vonage on Laravel's HTTP client, one call each, no SDK; a third provider is one class. The log is a table of its own with an Eloquent model you can swap, and tests fake the texts with FakesTexts. It comes with both admins, Filament and Nova.

Watch it ​

Two short lessons from the admin, narrated:

Connect Twilio: the keys, the sender, the webhooks, what is texted, a test
The log: delivered, failed and why, a STOP texted back, a number kept off by hand

Try it ​

The module comes with kitloom, for either admin. On a Filament site:

bash
composer require kitloom/text-messages kitloom/text-messages-filament
php artisan migrate

On a Nova site, the second package is kitloom/text-messages-nova. Open a sandbox in one click, with no sign-up: Filament or Nova. Every detail — Vonage, the WhatsApp templates' blanks, the agent's tools — is in the Text Messages guide.

Last updated:

kitloom — modules and themes for Laravel.
Contact · Pricing · Services · License · Refunds · Privacy · Community · YouTube · [email protected]