Added complete plugin documentation with visual mockups and expanded template
variable system with CONTEXT, DATE helpers, and default values.
Backend Changes:
- Extended template_parser.py to support all new template types
- Added PROMPT with default values: {{PROMPT:var|desc|default}}
- Added CONTEXT variables: {{CONTEXT:business_name}}, {{CONTEXT:owner_email}}
- Added DATE helpers: {{DATE:today}}, {{DATE:+7d}}, {{DATE:monday}}
- Implemented date expression evaluation for relative dates
- Updated compile_template to handle all template types
- Added context parameter for business data auto-fill
Frontend Changes:
- Created comprehensive HelpPluginDocs.tsx with Stripe-style API docs
- Added visual mockup of plugin configuration form
- Documented all template types with examples and benefits
- Added Command Reference section with allowed/blocked Python commands
- Documented all HTTP methods (GET, POST, PUT, PATCH, DELETE)
- Added URL whitelisting requirements and approval process
- Created Platform Staff management page with edit modal
- Added can_approve_plugins and can_whitelist_urls permissions
Platform Staff Features:
- List all platform_manager and platform_support users
- Edit user details with role-based permissions
- Superusers can edit anyone
- Platform managers can only edit platform_support users
- Permission cascade: users can only grant permissions they have
- Real-time updates via React Query cache invalidation
Documentation Highlights:
- 4 template types: PROMPT, CONTEXT, DATE, and automatic validation
- Visual form mockup showing exactly what users see
- All allowed control flow (if/elif/else, for, while, try/except, etc.)
- All allowed built-in functions (len, range, min, max, etc.)
- All blocked operations (import, exec, eval, class/function defs)
- Complete HTTP API reference with examples
- URL whitelisting process: contact pluginaccess@smoothschedule.com
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
11 KiB
Custom Script Examples - Quick Reference
Copy and paste these examples to get started quickly!
1. Send Weekly Summary Email
# Get appointments from last 7 days
from datetime import datetime, timedelta
end = datetime.now().strftime('%Y-%m-%d')
start = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
appointments = api.get_appointments(
start_date=start,
end_date=end,
limit=500
)
# Count by status
scheduled = sum(1 for a in appointments if a['status'] == 'SCHEDULED')
completed = sum(1 for a in appointments if a['status'] == 'COMPLETED')
canceled = sum(1 for a in appointments if a['status'] == 'CANCELED')
# Build report
report = f"""
Weekly Summary ({start} to {end})
Total Appointments: {len(appointments)}
- Scheduled: {scheduled}
- Completed: {completed}
- Canceled: {canceled}
Completion Rate: {(completed / len(appointments) * 100):.1f}%
"""
# Send it
api.send_email(
to='manager@yourbusiness.com',
subject=f'Weekly Summary - {start}',
body=report
)
result = {'total': len(appointments), 'completed': completed}
Schedule: 0 9 * * 1 (Every Monday at 9 AM)
2. Re-engage Inactive Customers
# Get appointments from last 90 days
from datetime import datetime, timedelta
cutoff = (datetime.now() - timedelta(days=90)).strftime('%Y-%m-%d')
recent_appointments = api.get_appointments(start_date=cutoff, limit=500)
# Get all customers
all_customers = api.get_customers(has_email=True, limit=200)
# Find who booked recently (simplified - in production use customer IDs)
recent_customer_emails = {apt['title'] for apt in recent_appointments}
# Find inactive customers
inactive = []
for customer in all_customers:
if customer['email'] not in recent_customer_emails:
inactive.append(customer)
# Send re-engagement emails (limit to 30 per run)
sent = 0
for customer in inactive[:30]:
message = f"""Hi {customer['name']},
We noticed it's been a while since your last visit!
We'd love to see you again. Book this week and get 20% off with code: COMEBACK20
Hope to see you soon!
"""
success = api.send_email(
to=customer['email'],
subject='We Miss You! 20% Off Inside',
body=message
)
if success:
sent += 1
api.log(f'Sent {sent} re-engagement emails')
result = {'inactive_found': len(inactive), 'emails_sent': sent}
Schedule: 0 10 * * 3 (Every Wednesday at 10 AM)
3. Alert on Low Bookings
# Get appointments for next 7 days
from datetime import datetime, timedelta
today = datetime.now().strftime('%Y-%m-%d')
next_week = (datetime.now() + timedelta(days=7)).strftime('%Y-%m-%d')
upcoming = api.get_appointments(
start_date=today,
end_date=next_week,
status='SCHEDULED',
limit=200
)
# If less than 10 appointments, send alert
if len(upcoming) < 10:
alert = f"""
⚠️ LOW BOOKING ALERT
Only {len(upcoming)} appointments scheduled for the next 7 days.
Recommendation: Run a promotion or send reminders to past customers.
This is below your normal booking rate.
"""
api.send_email(
to='owner@yourbusiness.com',
subject='⚠️ Low Booking Alert',
body=alert
)
result = {'alert_sent': True, 'upcoming_count': len(upcoming)}
else:
result = {'alert_sent': False, 'upcoming_count': len(upcoming)}
Schedule: 0 8 * * * (Every day at 8 AM)
4. Birthday Campaign
# Get all customers
customers = api.get_customers(has_email=True, limit=500)
# Today's date (simplified birthday check)
from datetime import datetime
today = datetime.now()
# Send birthday wishes (simplified - in production check actual birthdays)
birthday_customers = []
for customer in customers:
# In real usage, you'd have birthday field
# This is a placeholder
is_birthday = False # Replace with actual birthday check
if is_birthday:
birthday_customers.append(customer)
message = f"""Happy Birthday, {customer['name']}! 🎉
Celebrate with us! Get 25% off any service this week with code: BIRTHDAY25
We hope you have an amazing day!
"""
api.send_email(
to=customer['email'],
subject='🎉 Happy Birthday! Special Gift Inside',
body=message
)
api.log(f'Sent {len(birthday_customers)} birthday emails')
result = {'birthday_emails_sent': len(birthday_customers)}
Schedule: 0 9 * * * (Every day at 9 AM)
5. Appointment Reminder (Day Before)
# Get appointments for tomorrow
from datetime import datetime, timedelta
tomorrow_start = (datetime.now() + timedelta(days=1)).replace(hour=0, minute=0).strftime('%Y-%m-%d')
tomorrow_end = (datetime.now() + timedelta(days=1)).replace(hour=23, minute=59).strftime('%Y-%m-%d')
tomorrow_appointments = api.get_appointments(
start_date=tomorrow_start,
end_date=tomorrow_end,
status='SCHEDULED',
limit=100
)
# Send reminders
sent = 0
for apt in tomorrow_appointments:
# Extract time
time_str = apt['start_time'].split('T')[1][:5] # Get HH:MM
reminder = f"""Appointment Reminder
You have an appointment tomorrow at {time_str}.
Title: {apt['title']}
Time: {time_str}
See you then!
Reply CANCEL to cancel or RESCHEDULE to change the time.
"""
# In production, you'd get customer email from appointment
# This is simplified
customer_email = 'customer@example.com'
success = api.send_email(
to=customer_email,
subject='Reminder: Appointment Tomorrow',
body=reminder
)
if success:
sent += 1
result = {'reminders_sent': sent, 'appointments_tomorrow': len(tomorrow_appointments)}
Schedule: 0 18 * * * (Every day at 6 PM)
6. Monthly Performance Report
# Get last month's data
from datetime import datetime, timedelta
# Calculate last month
today = datetime.now()
first_of_this_month = today.replace(day=1)
last_month_end = (first_of_this_month - timedelta(days=1)).strftime('%Y-%m-%d')
last_month_start = (first_of_this_month - timedelta(days=31)).replace(day=1).strftime('%Y-%m-%d')
appointments = api.get_appointments(
start_date=last_month_start,
end_date=last_month_end,
limit=1000
)
# Calculate metrics
total = len(appointments)
completed = sum(1 for a in appointments if a['status'] == 'COMPLETED')
canceled = sum(1 for a in appointments if a['status'] == 'CANCELED')
no_show_rate = (canceled / total * 100) if total > 0 else 0
# Group by week
weekly_counts = {}
for apt in appointments:
# Get week number
date_str = apt['start_time'].split('T')[0]
weekly_counts[date_str[:7]] = weekly_counts.get(date_str[:7], 0) + 1
# Build report
report = f"""
Monthly Performance Report
Period: {last_month_start} to {last_month_end}
OVERVIEW
--------
Total Appointments: {total}
Completed: {completed}
Canceled: {canceled}
No-Show Rate: {no_show_rate:.1f}%
WEEKLY BREAKDOWN
----------------
"""
for week in sorted(weekly_counts.keys()):
report += f"{week}: {weekly_counts[week]} appointments\n"
report += f"\n{'📈' if completed > 50 else '📉'} "
report += "Great month!" if completed > 50 else "Consider increasing marketing"
# Send report
api.send_email(
to='owner@yourbusiness.com',
subject=f'Monthly Report - {last_month_start}',
body=report
)
result = {
'total': total,
'completed': completed,
'no_show_rate': round(no_show_rate, 2)
}
Schedule: 0 9 1 * * (First day of month at 9 AM)
7. VIP Customer Recognition
# Get appointments from last 6 months
from datetime import datetime, timedelta
six_months_ago = (datetime.now() - timedelta(days=180)).strftime('%Y-%m-%d')
appointments = api.get_appointments(start_date=six_months_ago, limit=1000)
# Count visits per customer (simplified)
customer_visits = {}
for apt in appointments:
# In production, extract actual customer ID
customer_id = apt.get('customer_id', 'unknown')
customer_visits[customer_id] = customer_visits.get(customer_id, 0) + 1
# Find VIP customers (5+ visits)
vip_count = sum(1 for visits in customer_visits.values() if visits >= 5)
# Get customers
customers = api.get_customers(has_email=True, limit=100)
# Send VIP recognition
sent = 0
for customer in customers:
visits = customer_visits.get(customer['id'], 0)
if visits >= 5:
message = f"""Hi {customer['name']},
You're officially a VIP! 🌟
You've visited us {visits} times in the last 6 months, and we truly appreciate your loyalty.
As a thank you, here's an exclusive 30% off code: VIP30
Valid for your next 3 visits!
Thank you for being amazing!
"""
success = api.send_email(
to=customer['email'],
subject='🌟 You are a VIP Customer!',
body=message
)
if success:
sent += 1
result = {'vip_customers': vip_count, 'emails_sent': sent}
Schedule: 0 10 1 * * (First of month at 10 AM)
8. Capacity Optimization Alert
# Get next 30 days of appointments
from datetime import datetime, timedelta
today = datetime.now().strftime('%Y-%m-%d')
thirty_days = (datetime.now() + timedelta(days=30)).strftime('%Y-%m-%d')
upcoming = api.get_appointments(
start_date=today,
end_date=thirty_days,
status='SCHEDULED',
limit=500
)
# Group by date
daily_bookings = {}
for apt in upcoming:
date = apt['start_time'].split('T')[0]
daily_bookings[date] = daily_bookings.get(date, 0) + 1
# Find issues
overbooked = []
underbooked = []
for date, count in daily_bookings.items():
if count > 15: # More than 15 per day = overbooked
overbooked.append(f"{date}: {count} appointments")
elif count < 3: # Less than 3 = underbooked
underbooked.append(f"{date}: {count} appointments")
# Send alert if needed
if overbooked or underbooked:
alert = "Capacity Alert\n\n"
if overbooked:
alert += "⚠️ OVERBOOKED DAYS:\n"
alert += "\n".join(overbooked)
alert += "\n\nConsider adding staff or limiting bookings.\n\n"
if underbooked:
alert += "📉 UNDERBOOKED DAYS:\n"
alert += "\n".join(underbooked)
alert += "\n\nConsider running promotions.\n"
api.send_email(
to='manager@yourbusiness.com',
subject='Capacity Alert - Action Needed',
body=alert
)
result = {
'overbooked_days': len(overbooked),
'underbooked_days': len(underbooked)
}
Schedule: 0 7 * * 1 (Every Monday at 7 AM)
Tips for Success
- Start Simple - Copy one example and modify it
- Test First - Use "Execute Now" to test before scheduling
- Check Logs - Review execution logs for errors
- Add Logging - Use
api.log()to debug - Limit Batches - Don't send too many emails at once
- Schedule Wisely - Consider your business hours
Common Modifications
Change Email Content
# Replace the message string with your own text
message = f"""Your custom message here
Use {customer['name']} for personalization
"""
Adjust Date Ranges
# Change the number of days
days_back = 30 # Instead of 7, 14, 90, etc.
start = (datetime.now() - timedelta(days=days_back)).strftime('%Y-%m-%d')
Filter by Status
# Only get specific statuses
appointments = api.get_appointments(
status='COMPLETED', # or 'SCHEDULED', 'CANCELED'
limit=100
)
Limit Results
# Process fewer customers
customers = api.get_customers(limit=20) # Instead of 100
Happy automating! 🚀