Scripts & Utilities
Utility scripts for data syncing and maintenance
Scripts & Utilities
The backend/scripts directory contains utility scripts for SynapseAI to maintain and sync data across different services.
Voucherify to Commercetools Sync
Overview
The sync_voucherify_promotions.py script fetches all active promotions from Voucherify and synchronizes them to Commercetools as Cart Discounts and Discount Codes.
This enables promotions created in Voucherify to be automatically applied during checkout in Commercetools.
Use Case
When you create a promotion campaign in Voucherify (e.g., "10% off for bulk orders"), you need that promotion to be available in Commercetools so customers can use it during checkout. This script automates that synchronization.
Prerequisites
Required Environment Variables:
Add these to your .env file:
# CommerceTools
CT_API_URL=https://api.us-central1.gcp.commercetools.com
CT_PROJECT_KEY=your-project-key
CT_CLIENT_ID=your-client-id
CT_CLIENT_SECRET=your-client-secret
CT_AUTH_URL=https://auth.us-central1.gcp.commercetools.com
CT_SCOPES=manage_discount_codes manage_orders view_project_settings
# Voucherify
VOUCHERIFY_MCP_BASE_URL=http://localhost:3002
VOUCHERIFY_APP_ID=your-app-id
VOUCHERIFY_APP_TOKEN=your-app-tokenRequired Permissions:
- Commercetools:
manage_discount_codes - Voucherify: Read access to campaigns
Usage
Run the script from the project root:
cd backend
python scripts/sync_voucherify_promotions.pyWhat It Does
The script performs the following operations:
- Fetches Promotions: Retrieves all active promotions from Voucherify via the MCP client
- Checks Existing: Verifies if each promotion already exists in Commercetools (by discount code)
- Creates Discounts: For new promotions, creates:
- Cart Discount in Commercetools
- Discount Code linked to the Cart Discount
- Skips Duplicates: Avoids creating duplicate promotions
- Reports Summary: Provides detailed output of synced, skipped, and failed promotions
Promotion Mapping
The script maps Voucherify fields to Commercetools fields:
| Voucherify Field | Commercetools Field | Description |
|---|---|---|
promotion.id | Discount Code code | Unique promotion identifier |
redeemable_details.public_banner | Cart Discount name | Display name |
redeemable_details.alternative_description | Cart Discount description | Detailed description |
result.discount.type (PERCENT) | relative discount type | Percentage discount |
result.discount.type (AMOUNT) | absolute discount type | Fixed amount discount |
result.discount.percent_off | permyriad value | Percentage × 100 |
result.discount.amount_off | centAmount value | Amount in cents |
Example Output
============================================================
Starting Voucherify → CommerceTools Promotion Sync
============================================================
Fetching promotions from Voucherify...
Found 5 promotions in Voucherify
[1/5] Processing promotion...
Processing promotion: Summer Sale (ID: promo_abc123)
Type: PERCENT, Value: 10
Status: SYNCED ✓
[2/5] Processing promotion...
Processing promotion: Winter Discount (ID: promo_def456)
Type: AMOUNT, Value: 1000
Discount code 'promo_def456' already exists in CommerceTools
Status: SKIPPED (already exists)
[3/5] Processing promotion...
Processing promotion: Bulk Order Discount (ID: promo_ghi789)
Type: PERCENT, Value: 15
Status: SYNCED ✓
[4/5] Processing promotion...
Processing promotion: Flash Sale (ID: promo_jkl012)
Type: AMOUNT, Value: 500
Status: SYNCED ✓
[5/5] Processing promotion...
Processing promotion: VIP Discount (ID: promo_mno345)
Type: PERCENT, Value: 20
Status: SYNCED ✓
============================================================
Sync Complete - Summary:
============================================================
Total promotions found: 5
Successfully synced: 4
Skipped (existing): 1
Failed: 0
============================================================Discount Types
Percentage Discount
Voucherify:
{
"discount": {
"type": "PERCENT",
"percent_off": 10
}
}Commercetools:
{
"value": {
"type": "relative",
"permyriad": 1000
}
}Fixed Amount Discount
Voucherify:
{
"discount": {
"type": "AMOUNT",
"amount_off": 1000
}
}Commercetools:
{
"value": {
"type": "absolute",
"money": [{
"currencyCode": "USD",
"centAmount": 1000
}]
}
}Error Handling
The script includes comprehensive error handling:
Missing Credentials:
Error: Missing CommerceTools configuration
Please ensure CT_CLIENT_ID, CT_CLIENT_SECRET, and CT_PROJECT_KEY are set in .envExisting Promotions:
Discount code 'promo_abc123' already exists in CommerceTools
Status: SKIPPED (already exists)Individual Failures:
[3/5] Processing promotion...
Error creating discount: HTTP 403 Forbidden
Status: FAILED ✗
Continuing with remaining promotions...Network Issues:
Error: Cannot connect to Voucherify MCP server
Please ensure VOUCHERIFY_MCP_BASE_URL is correct and server is runningTroubleshooting
Issue: "Missing CommerceTools configuration"
Cause: Environment variables not set
Solution:
# Check .env file exists
ls -la backend/.env
# Verify variables are set
cat backend/.env | grep CT_Issue: "HTTP 403 Forbidden" when creating discounts
Cause: Missing manage_discount_codes scope
Solution:
# Update .env with correct scopes
CT_SCOPES=manage_products manage_orders manage_discount_codes view_project_settingsIssue: "No promotions found in Voucherify"
Cause:
- Voucherify MCP server not running
- Wrong base URL
- No active campaigns in Voucherify
Solution:
# Check MCP server is running
curl http://localhost:3002/health
# Verify Voucherify credentials
# Check VOUCHERIFY_MCP_BASE_URL in .env
# Ensure you have active campaigns in VoucherifyIssue: "Promotion structure doesn't match expected format"
Cause: Voucherify API response format changed
Solution:
# The script handles multiple response structures
# Check logs for the actual response format
# Update fetch_voucherify_promotions() if neededIssue: Script runs but promotions don't appear in Commercetools
Cause:
- Wrong project key
- Insufficient permissions
- API endpoint incorrect
Solution:
# Verify CT connection
curl -X POST https://auth.us-central1.gcp.commercetools.com/oauth/token \
-u "${CT_CLIENT_ID}:${CT_CLIENT_SECRET}" \
-d "grant_type=client_credentials"
# Check project key
echo $CT_PROJECT_KEY
# Verify scopes include manage_discount_codes
echo $CT_SCOPESScheduling
For automated syncing, set up a cron job or scheduled task:
Cron Example (runs daily at 2 AM):
# Edit crontab
crontab -e
# Add line:
0 2 * * * cd /path/to/backend && /usr/bin/python scripts/sync_voucherify_promotions.py >> /var/log/voucherify-sync.log 2>&1AWS EventBridge (for production):
resource "aws_cloudwatch_event_rule" "sync_promotions" {
name = "sync-voucherify-promotions"
description = "Trigger promotion sync daily"
schedule_expression = "cron(0 2 * * ? *)"
}
resource "aws_cloudwatch_event_target" "sync_promotions" {
rule = aws_cloudwatch_event_rule.sync_promotions.name
target_id = "SyncPromotionsLambda"
arn = aws_lambda_function.sync_promotions.arn
}Advanced Usage
Dry Run Mode
Test the script without making changes:
# Add at the beginning of the script
DRY_RUN = True
# In create_discount function:
if DRY_RUN:
print(f"[DRY RUN] Would create discount: {discount_data}")
returnFilter by Campaign
Sync only specific campaigns:
# Add campaign filter
ALLOWED_CAMPAIGNS = ["summer-sale", "bulk-discount"]
# In main sync loop:
if promotion_id not in ALLOWED_CAMPAIGNS:
continueCustom Mapping
Modify the mapping logic for custom fields:
def map_voucherify_to_ct(voucherify_promotion):
"""Custom mapping logic"""
# Add custom fields
# Modify discount calculation
# Apply business rules
passFuture Scripts
Planned Utilities
Product Sync Script (sync_products.py):
- Sync products from external sources to Commercetools
- Update product inventory levels
- Sync product images and descriptions
Order Export Script (export_orders.py):
- Export orders for accounting
- Generate reports for analytics
- Archive historical data
Customer Import Script (import_customers.py):
- Bulk import customers from CSV
- Migrate from legacy systems
- Update customer segments
Cache Warm Script (warm_cache.py):
- Pre-populate Redis cache
- Warm up product catalog
- Prepare for high-traffic events
Contributing
When creating new scripts:
- Follow naming convention:
action_resource.py - Add comprehensive error handling
- Include progress indicators
- Provide detailed logging
- Document in this guide
- Add example output
- Include troubleshooting section
Script Template
#!/usr/bin/env python3
"""
Script Name: action_resource.py
Description: Brief description of what this script does
Author: Your Name
Date: YYYY-MM-DD
"""
import os
import sys
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
def validate_config():
"""Validate required configuration"""
required = ["VAR1", "VAR2"]
missing = [var for var in required if not os.getenv(var)]
if missing:
print(f"Error: Missing required variables: {', '.join(missing)}")
sys.exit(1)
def main():
"""Main execution function"""
print("=" * 60)
print("Starting Script Name")
print("=" * 60)
validate_config()
try:
# Main logic here
pass
except Exception as e:
print(f"Error: {e}")
sys.exit(1)
print("=" * 60)
print("Script Complete")
print("=" * 60)
if __name__ == "__main__":
main()Next Steps
- Backend Setup - Set up the backend environment
- Deployment - Deploy to production
- Architecture - Understand the system