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
| Context | Purpose | EndCustomer Actions |
|---|---|---|
EndCustomerContext | Contact storage and profile management | Create account, update profile, view history |
AvailabilityContext | Browse available time slots | View provider schedules, check slot availability |
AppointmentContext | Book and manage appointments | Create booking, cancel, reschedule, check-in via QR |
LeadContext | Join waitlist (EndCustomer action) | Request to join waitlist when slots full |
PaymentAccountContext | Manage payment methods | Add/remove cards, set default payment method |
PaymentContext | Process payments | Pay 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 servicesProviderContext- Shows provider profilesLocationContext- 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 detailsProviderContext- 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 slotsLeadContext.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 profileEndCustomerContext.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: "jane@example.com",
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 appointmentPaymentContractContext- Creates payment contractInvoiceContext- Generates deposit invoicePaymentContext- 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 tochecked_inMessageContext- 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 checkoutInvoiceContext- Creates balance invoicePaymentContext- 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 paymentInvoiceContext- Creates tip invoicePaymentContext- 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 appointmentPaymentContext- 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 timeAvailabilityContext- 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/2TransactionContext.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: "guest@example.com",
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
Related Capabilities
- Merchant Operations - Merchant staff capabilities
- Platform Operations - Platform staff capabilities
Related API Endpoints
See the API Reference for self-serve endpoints:
GET /api/services- Browse available servicesGET /api/bookings/availability- Check available slotsPOST /api/bookings- Create booking with depositPOST /api/end-customers- Create customer profilePOST /api/payment-accounts- Add payment method