Skip to main content

EndCustomer Self-Serve

Self-service capabilities for end customers to browse services, book appointments, manage their profile, and handle payments without merchant staff assistance.

Overview

EndCustomer Self-Serve encompasses all actions that end customers can perform on their own through the booking page or customer portal:

  • Browse services and providers
  • Check real-time availability
  • Book and manage appointments
  • Join waitlists when slots are unavailable
  • Add and manage payment methods
  • Complete checkout with deposit, balance, and tip payments
  • View appointment history and invoices

Contexts

ContextPurposeEndCustomer Actions
EndCustomerContextContact storage and profile managementCreate account, update profile, view history
AvailabilityContextBrowse available time slotsView provider schedules, check slot availability
AppointmentContextBook and manage appointmentsCreate booking, cancel, reschedule, check-in via QR
LeadContextJoin waitlist (EndCustomer action)Request to join waitlist when slots full
PaymentAccountContextManage payment methodsAdd/remove cards, set default payment method
PaymentContextProcess paymentsPay deposit, balance, tip at checkout

Booking Journey

1. Discovery & Browse

EndCustomer Actions:

  • Visit merchant's booking page (e.g., serenity-spa.zoca.app)
  • Browse service catalog with descriptions and pricing
  • View provider profiles (if merchant enables this)
  • Check business hours and location information

Contexts Used:

  • ServiceContext - Lists available services
  • ProviderContext - Shows provider profiles
  • LocationContext - Displays location information

2. Select Service & Provider

EndCustomer Actions:

  • Choose desired service (e.g., "Haircut & Style - $100")
  • Optionally select specific provider or choose "Any available"
  • View service duration and pricing

Contexts Used:

  • ServiceContext - Service details
  • ProviderContext - Provider selection

3. Check Availability

EndCustomer Actions:

  • View calendar with available dates
  • Select date to see available time slots
  • If no slots available, option to join waitlist

Contexts Used:

  • AvailabilityContext.list_available_slots/3 - Fetches bookable slots
  • LeadContext.create_lead/1 - Adds to waitlist (EndCustomer self-serve)

Example:

# EndCustomer views availability for a service
AvailabilityContext.list_available_slots(
merchant_id,
service_id,
date_range: {~D[2025-01-20], ~D[2025-01-27]}
)

# Returns:
{:ok, [
%{starts_at: ~U[2025-01-20 14:00:00Z], ends_at: ~U[2025-01-20 15:00:00Z], provider_id: "..."},
%{starts_at: ~U[2025-01-20 15:00:00Z], ends_at: ~U[2025-01-20 16:00:00Z], provider_id: "..."}
]}

4. Enter Contact Information

EndCustomer Actions:

  • Enter name, email, phone number
  • Create account or continue as guest (if merchant allows)
  • Optionally save profile for future bookings

Contexts Used:

  • EndCustomerContext.create_end_customer/1 - Creates customer profile
  • EndCustomerContext.update_end_customer/2 - Updates existing profile

Example:

# EndCustomer creates profile
EndCustomerContext.create_end_customer(%{
merchant_id: merchant.id,
tenant_id: tenant.id,
name: "Jane Doe",
email: "[email protected]",
phone: "+15551234567"
})

5. Add Payment Method

EndCustomer Actions:

  • Enter credit card details via Stripe Payment Element
  • Card details never touch SCP servers (PCI compliant)
  • Option to save card for future use
  • Set as default payment method

Contexts Used:

  • PaymentAccountContext.create_payment_account/1 - Saves payment method
  • Stripe Payment Element (frontend) - Handles card input securely

Example:

# After Stripe creates PaymentMethod (pm_abc123)
PaymentAccountContext.create_payment_account(%{
end_customer_id: customer.id,
plugin_id: stripe_plugin.id,
external_id: "pm_abc123", # Stripe PaymentMethod ID
type: :card,
brand: "visa",
last4: "4242",
exp_month: 12,
exp_year: 2027,
is_default: true
})

6. Pay Deposit & Confirm Booking

EndCustomer Actions:

  • Review booking summary (service, provider, time, price)
  • Pay required deposit (e.g., 40% of $100 = $40)
  • Receive confirmation via SMS and email

Contexts Used:

  • AvailabilityContext.book_appointment/4 - Creates appointment
  • PaymentContractContext - Creates payment contract
  • InvoiceContext - Generates deposit invoice
  • PaymentContext - Processes deposit charge

Flow:

# EndCustomer confirms booking
AvailabilityContext.book_appointment(%{
end_customer_id: customer.id,
service_id: service.id,
provider_id: provider.id,
appointment_time: ~U[2025-01-20 14:00:00Z],
payment_account_id: card.id
})

# Behind the scenes:
# 1. Create Appointment (status: pending_payment)
# 2. Create PaymentContract (amount: $100, deposit: $40)
# 3. Create Invoice (category: :deposit, amount: $40)
# 4. Charge deposit via PaymentContext
# 5. Update Appointment (status: confirmed)
# 6. Send confirmation SMS/Email

Day-of-Service Actions

7. Check-In

EndCustomer Actions:

  • Receive SMS reminder 2 hours before appointment with QR code
  • Scan QR code to check in upon arrival
  • Alternatively: Reply to SMS or use kiosk (future)

Contexts Used:

  • AppointmentContext.check_in/2 - Updates status to checked_in
  • MessageContext - Sends T-2h reminder with QR code

Example:

# EndCustomer scans QR code
AppointmentContext.check_in(appointment.id, %{
check_in_method: :qr_code,
check_in_time: DateTime.utc_now()
})

# Status: confirmed → checked_in

8. Service Delivery

Merchant Action (not EndCustomer):

  • Provider delivers service
  • Marks service as complete

EndCustomer Experience:

  • Receives notification that service is complete
  • Ready for checkout

Checkout & Payment

9. Pay Balance

EndCustomer Actions:

  • View checkout screen with itemized charges
  • Remaining balance charged automatically (service - deposit)
  • Example: $100 - $40 = $60 balance due

Contexts Used:

  • AppointmentContext.process_checkout/2 - Initiates checkout
  • InvoiceContext - Creates balance invoice
  • PaymentContext - Charges balance

Example:

# Checkout triggered (merchant-initiated or automatic)
AppointmentContext.process_checkout(appointment, %{
payment_account_id: customer.default_payment_account.id
})

# Creates Invoice (category: :balance, amount: $60)
# Charges $60 to saved card

10. Add Tip

EndCustomer Actions:

  • Select tip amount: 15%, 18%, 20%, or custom
  • Example: 18% of $100 = $18
  • Tip charged to saved payment method

Contexts Used:

  • AppointmentContext.collect_tip/2 - Processes tip payment
  • InvoiceContext - Creates tip invoice
  • PaymentContext - Charges tip

Example:

# EndCustomer selects 18% tip
AppointmentContext.collect_tip(appointment, %{
tip_percentage: 18,
payment_account_id: customer.default_payment_account.id
})

# Creates Invoice (category: :tip, amount: $18)
# Charges $18 to saved card
# Total paid: $40 (deposit) + $60 (balance) + $18 (tip) = $118

11. View Receipt

EndCustomer Actions:

  • Receive final receipt via SMS and email
  • View itemized breakdown in customer portal
  • Download PDF receipt

Receipt Details:

Serenity Spa & Wellness
123 Main St, Los Angeles, CA
Date: Jan 20, 2025 at 2:00 PM

Service: Haircut & Style
Provider: Jane Smith
Duration: 60 minutes

Subtotal: $100.00
Deposit (paid): -$40.00
Balance: $60.00
Tip (18%): $18.00
------------------------
Total Paid: $78.00
Total Charged: $118.00

Payment Method: Visa ****4242

View Full Receipt | Book Again | Leave Review

Appointment Management

Cancel Appointment

EndCustomer Actions:

  • View upcoming appointments in portal
  • Cancel appointment with refund based on policy
  • Receive refund confirmation

Contexts Used:

  • AppointmentContext.cancel_appointment/2 - Cancels appointment
  • PaymentContext - Processes refund based on policy

Refund Policy Examples:

  • 24h notice: 100% deposit refunded

  • <24h notice: 50% deposit refunded
  • <2h notice: 0% deposit refunded

Example:

# EndCustomer cancels 48 hours before appointment
AppointmentContext.cancel_appointment(appointment, %{
cancelled_by: end_customer.id,
reason: "Scheduling conflict"
})

# Calculates refund: 100% of $40 = $40
# Processes refund via Stripe
# Sends confirmation email

Reschedule Appointment

EndCustomer Actions:

  • Select new date and time from available slots
  • Keep same service and provider
  • No additional charges if within policy window

Contexts Used:

  • AppointmentContext.reschedule_appointment/2 - Updates appointment time
  • AvailabilityContext - Shows new available slots

Waitlist (Join Only)

Join Waitlist

EndCustomer Actions:

  • When desired time slot is full, click "Join Waitlist"
  • Enter contact information and preferences
  • Receive confirmation that request was submitted
  • Wait for merchant/AI agent to approve and notify

Contexts Used:

  • LeadContext.create_lead/1 - Creates waitlist entry

Example:

# EndCustomer joins waitlist for full slot
LeadContext.create_lead(%{
merchant_id: merchant.id,
end_customer_id: customer.id,
service_id: service.id,
preferred_date: ~D[2025-01-20],
preferred_time: "14:00",
status: :waitlist,
source: :self_serve
})

# Status: :waitlist (pending merchant/AI approval)

Note: Managing waitlists (approving, contacting, converting to bookings) is handled by Merchant Operations or AI agents. See Merchant Operations for waitlist management capabilities.


Payment Method Management

Add Card

EndCustomer Actions:

  • Navigate to payment methods in portal
  • Click "Add Card"
  • Enter card details via Stripe Payment Element
  • Save card for future bookings

Contexts Used:

  • PaymentAccountContext.create_payment_account/1

Remove Card

EndCustomer Actions:

  • View saved payment methods
  • Remove card from account
  • Card deleted from Stripe

Contexts Used:

  • PaymentAccountContext.delete_payment_account/1

Set Default Card

EndCustomer Actions:

  • Select card to use as default for future bookings
  • Default card charged automatically at checkout

Contexts Used:

  • PaymentAccountContext.update_payment_account/2

Customer Portal

View Appointment History

EndCustomer Actions:

  • View all past and upcoming appointments
  • Filter by status (completed, cancelled, upcoming)
  • View appointment details and receipts

Contexts Used:

  • AppointmentContext.list_appointments_for_customer/2

View Payment History

EndCustomer Actions:

  • View all past payments and invoices
  • Download receipts as PDF
  • View refund history

Contexts Used:

  • InvoiceContext.list_invoices_for_customer/2
  • TransactionContext.list_transactions_for_customer/2

Guest Checkout vs. Account

Guest Checkout (if enabled by merchant)

EndCustomer Experience:

  • Book appointment without creating account
  • Enter contact info only
  • Save card for this booking only (not future bookings)
  • Limited access to portal (view confirmation only)

Account Creation

Benefits for EndCustomers:

  • Save payment methods for future bookings
  • View appointment history
  • Faster rebooking experience
  • Manage profile information
  • Join loyalty programs (future)

Example:

# Guest checkout
AvailabilityContext.book_appointment(%{
guest_email: "[email protected]",
guest_name: "Guest User",
guest_phone: "+15551234567",
# ... rest of booking details
})

# Account-based booking
AvailabilityContext.book_appointment(%{
end_customer_id: existing_customer.id,
# ... rest of booking details
})

Mobile Experience

All EndCustomer Self-Serve features are mobile-optimized:

  • Responsive Design: Booking page adapts to mobile screens
  • Touch-Friendly: Large buttons for service/time selection
  • QR Code Scanning: Native camera integration for check-in
  • Mobile Wallet Support: Apple Pay, Google Pay
  • SMS Links: Direct links to booking page in reminders

See the API Reference for self-serve endpoints:

  • GET /api/services - Browse available services
  • GET /api/bookings/availability - Check available slots
  • POST /api/bookings - Create booking with deposit
  • POST /api/end-customers - Create customer profile
  • POST /api/payment-accounts - Add payment method