> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dmly.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Client portal

> Let a returning client sign in with a WhatsApp one-time code to see their booking history, without a password.

The client portal is a small self-service page attached to your booking page: a client enters
their phone number, gets a one-time code on WhatsApp, and signs in to see every booking they've
made with you. There's no password to set or forget: the code *is* the login. It's off by
default; turn it on when you want returning clients to check their own history instead of asking
you.

<Note>
  The portal shows **booking history only**: a list of appointments and their status. It doesn't
  show invoices, payments or gift card balances. For those, point a client at their
  [invoice](/finance/invoices) or [pay link](/finance/payments-and-gateways) directly.
</Note>

## Turn it on

<Steps>
  <Step title="Open Appointments settings">
    Go to **Appointments → Settings**, staying on the **Appointment** sub-tab, and find the
    **Client portal** panel.
  </Step>

  <Step title="Enable client portal">
    Switch on **Enable client portal**. This immediately adds a **Log in** link to your booking
    pages, visible to every visitor from the moment you flip it on, whether or not you can
    actually deliver a code yet.
  </Step>

  <Step title="Make sure you can actually deliver a code">
    If the panel shows *No way to send login codes yet*, connect [WhatsApp](/channels/whatsapp)
    and get the login-code template approved, or connect an [SMS gateway](/channels/sms), before
    real visitors see that link. DMLY doesn't hide **Log in** just because there's nowhere to
    send a code yet: a client who clicks it before you've connected a channel lands on an error
    page instead of a login form. Turn the portal on right before, or right after, connecting a
    channel, not days ahead of it.
  </Step>

  <Step title="Decide whether booking should require it (optional)">
    **Require login to book** hides the whole booking flow behind sign-in: a visitor has to enter
    a phone number and verify a code before they can pick a service or a time. Leave it off (the
    default) to let anyone book without an account, same as today, and offer the portal purely as
    an extra for people who want to check their history.
  </Step>
</Steps>

<Warning>
  **Require login to book** only takes effect while **Enable client portal** is also on; turning
  the portal off turns this back off too, so a booking page can never be stranded behind a login
  nobody can complete. The same fail-safe applies if your WhatsApp template stops being approved
  and no SMS gateway is connected: DMLY lets visitors book without signing in rather than lock
  them out.
</Warning>

## What a client does

<Steps>
  <Step title="Selects Log in">
    From your booking page (the landing page or a single service's page), they select **Log in**
    in the top corner.
  </Step>

  <Step title="Enters their phone number">
    Any phone number works here, not only one you already have on file; signing in through the
    portal is how a brand-new visitor can get an account too. A submitted number always gets the
    same response, *"If that number can receive messages, we've sent a 6-digit code."* This is
    deliberate, so the login page never reveals whether a number belongs to an existing client.
  </Step>

  <Step title="Gets a 6-digit code on WhatsApp">
    Sent as a WhatsApp authentication message with a **Copy code** button, or by SMS if you don't
    have WhatsApp connected. The code expires after 10 minutes, and they can request a fresh one
    if it lapses; DMLY makes them wait briefly between requests so the number isn't spammed with
    codes.
  </Step>

  <Step title="Enters the code and is signed in">
    A wrong code just asks them to try again; too many wrong guesses burns that code and they
    need to request a new one. Once verified, they land on **My bookings**.
  </Step>
</Steps>

## What's on the portal page

Signed in, a client sees:

* **My bookings**: every booking on their record, most recent first, each with the service
  name, date and time, and a status badge (**Upcoming**, **Past** or **Cancelled**).
* **View**, on each booking: opens that booking's own manage page, where they can cancel or
  reschedule within your [cancellation and reschedule deadlines](/appointments/booking-page),
  exactly as if they'd followed the link from their confirmation message.
* **Book a new appointment**: takes them straight back to your booking page.
* **Log out**.

A client with no bookings yet sees an empty state instead, and can still book from there.

<Note>
  A booking only shows up if it's linked to the same Contact record the phone number resolves to.
  A client who always books with the same phone number is fine; one who's booked before under a
  different number or a typed email won't see those older bookings until a booking is made on
  the number they log in with.
</Note>

## Troubleshooting

<Accordion title="There's no Log in link on the booking page">
  **Enable client portal** is off. Turn it on under **Appointments → Settings → Appointment →
  Client portal**.
</Accordion>

<Accordion title="Log in shows an error page instead of a login form">
  **Enable client portal** is on, but there's still no way to deliver a code: no approved
  WhatsApp login-code template and no connected SMS gateway. DMLY doesn't hide the **Log in**
  link while that's true, so a client who clicks it lands on a generic error page rather than the
  phone-entry form. Connect [WhatsApp](/channels/whatsapp) (with the login-code template
  approved) or an [SMS gateway](/channels/sms) and the same link starts working immediately.
  Nothing else to change.
</Accordion>

<Accordion title="A client reached the login page but the code never arrived">
  This is different from the link itself erroring (above): reaching the phone-entry form means a
  channel was connected at that moment. A code can still fail to arrive if they've hit DMLY's
  built-in limit on how many codes one number can request in a day, a guard against a number
  being spammed with codes; the page answers the same either way, *"If that number can receive
  messages, we've sent a 6-digit code,"* so it won't look like anything went wrong. If your
  WhatsApp login-code template stops being approved or your SMS gateway disconnects, they'll see
  an explicit "Login is temporarily unavailable" message instead. Either way: wait a few minutes
  and try again, and check that [WhatsApp](/channels/whatsapp) or your
  [SMS gateway](/channels/sms) is still connected.
</Accordion>

<Accordion title="&#x22;Please wait before requesting another code&#x22;">
  A client asked for a second code too soon after the first. This is a short, deliberate cooldown
  to stop a number being flooded with codes. Ask them to wait a minute and try again.
</Accordion>

<Accordion title="A client's booking history looks empty even though they've booked before">
  Their booking is very likely attached to a different phone number, or to an email-only Contact
  created from the booking page (a stranger who books without WhatsApp attached gets a
  lightweight Contact from their name and email; see [Booking page](/appointments/booking-page)).
  The portal matches purely on phone number, so it won't surface those older bookings until one
  is made against the number they're signing in with.
</Accordion>

<Columns cols={2}>
  <Card title="Booking page" icon="calendar-check" href="/appointments/booking-page">
    Where the Log in link lives, and how a booking's own manage page works.
  </Card>

  <Card title="Connect WhatsApp" icon="whatsapp" href="/channels/whatsapp">
    Needed to deliver the one-time login code as a WhatsApp message.
  </Card>

  <Card title="SMS" icon="comment-sms" href="/channels/sms">
    A fallback way to deliver the code if WhatsApp isn't connected.
  </Card>

  <Card title="Appointments overview" icon="calendar-days" href="/appointments/overview">
    How services, staff and bookings fit together.
  </Card>
</Columns>
