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>
15 KiB
Custom Scripting Guide
Create your own automations with safe, powerful scripting! Write Python-like code with if/else statements, loops, and variables to automate your business processes.
🎯 What You Can Do
- Access Your Data: Get appointments, customers, and more
- Write Logic: Use if/else, loops, and variables
- Send Emails: Contact customers automatically
- Create Reports: Generate custom analytics
- Call APIs: Integrate with external services (approved domains)
🔒 Safety Features
We protect your data and our servers with:
- No Infinite Loops: Automatically stopped after 10,000 iterations
- Execution Timeout: Scripts limited to 30 seconds
- API Rate Limits: Maximum 50 API calls per execution
- Memory Limits: 50MB maximum
- No File Access: Can't read/write files
- No Code Injection: Can't use eval, exec, or import
- Sandboxed: Runs in isolated environment
📚 Available API Methods
api.get_appointments(**filters)
Get appointments for your business.
Parameters:
status- Filter by status ('SCHEDULED', 'COMPLETED', 'CANCELED')start_date- Filter by start date ('YYYY-MM-DD')end_date- Filter by end date ('YYYY-MM-DD')limit- Maximum results (default: 100, max: 1000)
Returns: List of appointment dictionaries
Example:
# Get all scheduled appointments
appointments = api.get_appointments(status='SCHEDULED')
# Get appointments from last week
from datetime import datetime, timedelta
start = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
recent = api.get_appointments(start_date=start, limit=50)
api.get_customers(**filters)
Get customers for your business.
Parameters:
limit- Maximum results (default: 100, max: 1000)has_email- Only customers with email addresses (True/False)
Returns: List of customer dictionaries
Example:
# Get all customers with emails
customers = api.get_customers(has_email=True)
# Get first 50 customers
top_customers = api.get_customers(limit=50)
api.send_email(to, subject, body)
Send an email to a customer.
Parameters:
to- Email address or customer IDsubject- Email subject (max 200 characters)body- Email body (max 10,000 characters)
Returns: True if sent successfully
Example:
# Send to email address
api.send_email(
to='customer@example.com',
subject='Special Offer',
body='Hello! Here is a special offer just for you...'
)
# Send to customer by ID
api.send_email(
to=123,
subject='Appointment Reminder',
body='Your appointment is tomorrow at 2 PM'
)
api.create_appointment(title, start_time, end_time, **kwargs)
Create a new appointment.
Parameters:
title- Appointment titlestart_time- Start datetime (ISO format: '2025-01-15T10:00:00')end_time- End datetime (ISO format: '2025-01-15T11:00:00')notes- Optional notes
Returns: Created appointment dictionary
Example:
apt = api.create_appointment(
title='Follow-up Consultation',
start_time='2025-01-20T14:00:00',
end_time='2025-01-20T15:00:00',
notes='Automated follow-up'
)
api.log(message)
Log a message for debugging.
Example:
api.log('Script started')
api.log(f'Found {len(appointments)} appointments')
api.http_get(url, headers=None)
Make HTTP GET request to approved domains.
Parameters:
url- URL to fetch (must be approved)headers- Optional headers dictionary
Returns: Response text
Example:
# Call Slack webhook
response = api.http_get(
'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
)
Helper Methods
# Count items
count = api.count(appointments)
# Sum numbers
total = api.sum([10, 20, 30])
# Filter with condition
active = api.filter(customers, lambda c: c['email'] != '')
📝 Script Examples
Example 1: Simple Appointment Count
# Get all appointments
appointments = api.get_appointments(limit=500)
# Count by status
scheduled = 0
completed = 0
for apt in appointments:
if apt['status'] == 'SCHEDULED':
scheduled += 1
elif apt['status'] == 'COMPLETED':
completed += 1
# Log results
api.log(f"Scheduled: {scheduled}, Completed: {completed}")
# Return result
result = {
'scheduled': scheduled,
'completed': completed,
'total': len(appointments)
}
Example 2: Conditional Email Campaign
# Get customers
customers = api.get_customers(has_email=True, limit=100)
# Get recent appointments
from datetime import datetime, timedelta
cutoff = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d')
recent_apts = api.get_appointments(start_date=cutoff)
# Find customers who booked recently
recent_customer_ids = set()
for apt in recent_apts:
# In real usage, you'd extract customer ID from appointment
pass
# Send emails to inactive customers
sent = 0
for customer in customers:
# If customer hasn't booked recently
if customer['id'] not in recent_customer_ids:
success = api.send_email(
to=customer['email'],
subject='We Miss You!',
body=f"Hi {customer['name']},\n\nIt's been a while! Come back and get 15% off."
)
if success:
sent += 1
result = {'emails_sent': sent}
Example 3: Weekly Summary Report
# Get appointments from last 7 days
from datetime import datetime, timedelta
end_date = datetime.now().strftime('%Y-%m-%d')
start_date = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
appointments = api.get_appointments(
start_date=start_date,
end_date=end_date,
limit=500
)
# Group by day
daily_counts = {}
for apt in appointments:
# Extract date from ISO timestamp
date = apt['start_time'].split('T')[0]
daily_counts[date] = daily_counts.get(date, 0) + 1
# Build report
report = "Weekly Appointment Summary\n\n"
for date in sorted(daily_counts.keys()):
report += f"{date}: {daily_counts[date]} appointments\n"
report += f"\nTotal: {len(appointments)}"
# Send report
api.send_email(
to='manager@business.com',
subject='Weekly Summary',
body=report
)
result = {'total_appointments': len(appointments)}
Example 4: Smart Customer Segmentation
# Get all customers
customers = api.get_customers(has_email=True, limit=500)
# Get all appointments
appointments = api.get_appointments(limit=1000)
# Count visits per customer (simplified)
visit_counts = {}
for apt in appointments:
# In real usage, extract customer ID
customer_id = 'placeholder'
visit_counts[customer_id] = visit_counts.get(customer_id, 0) + 1
# Segment customers
new_customers = []
loyal_customers = []
for customer in customers:
visits = visit_counts.get(customer['id'], 0)
if visits == 1:
new_customers.append(customer)
elif visits >= 5:
loyal_customers.append(customer)
# Send different messages to each segment
for customer in new_customers:
api.send_email(
to=customer['email'],
subject='Welcome!',
body=f"Hi {customer['name']}, thanks for trying us! Here's 20% off your next visit."
)
for customer in loyal_customers:
api.send_email(
to=customer['email'],
subject='VIP Offer',
body=f"Hi {customer['name']}, you're a valued customer! Exclusive offer inside..."
)
result = {
'new_customers': len(new_customers),
'loyal_customers': len(loyal_customers)
}
Example 5: Dynamic Pricing Alert
# Get upcoming appointments
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'
)
# Count by day
daily_bookings = {}
for apt in upcoming:
date = apt['start_time'].split('T')[0]
daily_bookings[date] = daily_bookings.get(date, 0) + 1
# Find slow days (less than 3 bookings)
slow_days = []
for date, count in daily_bookings.items():
if count < 3:
slow_days.append(date)
# Alert manager
if slow_days:
message = f"Slow booking days detected:\n\n"
for date in slow_days:
count = daily_bookings[date]
message += f"{date}: only {count} booking(s)\n"
message += "\nConsider running a promotion!"
api.send_email(
to='manager@business.com',
subject='⚠️ Low Booking Alert',
body=message
)
result = {'slow_days': slow_days}
🎨 Using Script Templates
Pre-built templates make it even easier! Just fill in the parameters.
Example: Conditional Email Template
curl -X POST http://lvh.me:8000/api/scheduled-tasks/ \
-H "Content-Type: application/json" \
-d '{
"name": "VIP Customer Campaign",
"plugin_name": "script_template",
"plugin_config": {
"template": "conditional_email",
"parameters": {
"condition_field": "visits",
"condition_value": "5",
"email_subject": "You are a VIP!",
"email_body": "Hi {name}, you are one of our best customers!"
}
},
"schedule_type": "CRON",
"cron_expression": "0 10 * * 1"
}'
🚀 Creating a Scheduled Script
Via API
curl -X POST http://lvh.me:8000/api/scheduled-tasks/ \
-H "Content-Type: application/json" \
-d '{
"name": "My Custom Automation",
"description": "Weekly customer re-engagement",
"plugin_name": "custom_script",
"plugin_config": {
"script": "# Your Python code here\nappointments = api.get_appointments()\napi.log(f\"Found {len(appointments)} appointments\")\nresult = len(appointments)",
"description": "Counts appointments and logs the result"
},
"schedule_type": "CRON",
"cron_expression": "0 9 * * 1",
"status": "ACTIVE"
}'
Schedule Types
Every Monday at 9 AM:
{
"schedule_type": "CRON",
"cron_expression": "0 9 * * 1"
}
Every Hour:
{
"schedule_type": "INTERVAL",
"interval_minutes": 60
}
One-Time on Specific Date:
{
"schedule_type": "ONE_TIME",
"run_at": "2025-02-01T10:00:00Z"
}
📖 Built-in Functions
You can use these Python built-ins:
# Math
len([1, 2, 3]) # Length
min([1, 2, 3]) # Minimum
max([1, 2, 3]) # Maximum
sum([1, 2, 3]) # Sum
abs(-5) # Absolute value
round(3.14159, 2) # Round to 2 decimals
# Type conversion
int('42') # Convert to integer
float('3.14') # Convert to float
str(123) # Convert to string
bool(1) # Convert to boolean
# Collections
list((1, 2, 3)) # Create list
dict(a=1, b=2) # Create dictionary
range(10) # Number sequence
sorted([3, 1, 2]) # Sort list
reversed([1, 2, 3]) # Reverse list
# Iteration
enumerate(['a', 'b']) # Index and value
zip([1, 2], ['a', 'b']) # Combine lists
any([True, False]) # Any true?
all([True, True]) # All true?
❌ What's NOT Allowed
# ❌ Import statements
import os # Error!
# ❌ Eval/exec
eval('1 + 1') # Error!
# ❌ Function definitions (for now)
def my_function(): # Error!
pass
# ❌ Class definitions
class MyClass: # Error!
pass
# ❌ File operations
open('file.txt') # No file access!
# ❌ Network (except approved APIs)
requests.get('http://example.com') # Error!
🐛 Debugging Tips
Use Logging
api.log('Script started')
customers = api.get_customers()
api.log(f'Found {len(customers)} customers')
for customer in customers:
api.log(f'Processing {customer["name"]}')
# ... do something
api.log('Script finished')
Check Execution Logs
# Get logs for task #1
curl http://lvh.me:8000/api/scheduled-tasks/1/logs/
# Filter by status
curl http://lvh.me:8000/api/task-logs/?status=FAILED
Test Scripts Manually
# Execute task immediately (don't wait for schedule)
curl -X POST http://lvh.me:8000/api/scheduled-tasks/1/execute/
⚡ Performance Tips
1. Limit Data Fetching
# ❌ Bad: Fetch everything
appointments = api.get_appointments(limit=1000)
# ✅ Good: Fetch only what you need
appointments = api.get_appointments(
status='SCHEDULED',
start_date='2025-01-01',
limit=50
)
2. Use Efficient Loops
# ❌ Bad: Nested loops
for customer in customers:
for apt in appointments:
if apt['customer_id'] == customer['id']:
# ...
# ✅ Good: Build lookup first
customer_apts = {}
for apt in appointments:
cid = apt['customer_id']
if cid not in customer_apts:
customer_apts[cid] = []
customer_apts[cid].append(apt)
for customer in customers:
apts = customer_apts.get(customer['id'], [])
# Much faster!
3. Batch Operations
# ❌ Bad: Individual calls
for customer in customers:
api.send_email(customer['email'], 'Subject', 'Body')
# ✅ Good: Filter first, then send
active_customers = [c for c in customers if c['status'] == 'active']
for customer in active_customers:
api.send_email(customer['email'], 'Subject', 'Body')
💡 Common Use Cases
1. Abandoned Cart Recovery
# Find customers with unpaid appointments
unpaid = api.get_appointments(status='SCHEDULED')
# Send reminder emails
2. Birthday Campaigns
# Get customers with birthdays this week
# Send birthday wishes with discount code
3. Review Requests
# Get completed appointments from yesterday
# Send review request emails
4. Capacity Alerts
# Count upcoming appointments
# Alert if fully booked or too empty
5. Customer Lifecycle
# Identify customer segments (new, active, at-risk)
# Send targeted campaigns
🔐 Security Best Practices
-
Never hardcode secrets in scripts
- Use environment variables or settings
- Don't put API keys in code
-
Validate input data
email = customer.get('email', '') if '@' in email: api.send_email(email, 'Subject', 'Body') -
Limit batch sizes
# Don't spam - send max 50 emails per run customers = api.get_customers(limit=50) -
Handle errors gracefully
success = api.send_email(email, subject, body) if not success: api.log(f'Failed to send to {email}')
📊 Script Result Format
Your script should set a result variable with execution results:
# Your script logic here
appointments = api.get_appointments()
# Set result variable
result = {
'total': len(appointments),
'scheduled': 10,
'completed': 25,
'message': 'Processing completed successfully'
}
This result is stored in the execution log and can be used for tracking and analytics.
🆘 Getting Help
- Execution Failed? Check the error message in logs
- Need More API Methods? Contact support to request new features
- Performance Issues? Review the performance tips above
- Template Request? Suggest new templates to add
📈 Pricing
| Plan | Custom Scripts | Executions/Month | Support |
|---|---|---|---|
| Free | 1 active | 100 | Community |
| Pro | 5 active | 1,000 | |
| Business | Unlimited | Unlimited | Priority |
Start automating your business today! 🚀