Skip to content

Migrating from Your Legacy CEP

This guide maps legacy CEP concepts, APIs, and template syntax to their Synapse equivalents. If you are migrating existing flows and templates, use this as your reference.


Concept Mapping

Legacy CEPSynapseNotes
UserContactIdentified by external_id (your user ID)
UserAttributeContact propertiesproperties JSONB field on contact record
EventAttributeEvent attributesattributes JSON object in event payload
Smart Campaign / FlowFlowEvent-triggered multi-step journey
Template (Jinja2)Template (NLT)Human-readable syntax replaces Jinja2
SegmentSegmentFilter DSL with all/any grouping
Campaign StatsAnalyticsDelivery, open, click, bounce tracking
MOE_NOT_SENDrequired modifierSuppresses email if value is null
default('fallback')or "fallback"Provides a fallback value

Template Syntax Migration

Variables

Legacy CEP (Jinja2)Synapse (NLT)
{{UserAttribute['First Name']}}{the user's First Name}
{{UserAttribute['First Name']|default('Guest')}}{the user's First Name, or "Guest"}
{{EventAttribute['wics_open.Reference Number']}}{the Reference Number from the trigger event}
{{EventAttribute['wics_open.Reference Number']|default('MOE_NOT_SEND')}}{the Reference Number from the trigger event, required}

Conditionals

Legacy CEP (Jinja2)Synapse (NLT)
{% if UserAttribute['Plan'] == 'premium' %}{if the user's Plan is premium}
{% elif UserAttribute['Plan'] == 'starter' %}{else if the user's Plan is starter}
{% else %}{else}
{% endif %}{end if}

Loops

Legacy CEP (Jinja2)Synapse (NLT)
{% for item in UserAttribute['Orders'] %}{for item in the user's Orders}
{{ item['Name'] }}{item.Name}
{% endfor %}{end for}

Formatting

Legacy CEP (Jinja2)Synapse (NLT)
{{ amount | int }}{the Amount, as "number"}
Custom Jinja filter for currency{the Amount, as "currency"}
Custom date formatting{the Date, as "long date"}

MOE_NOT_SEND to Required

In the legacy platform, |default('MOE_NOT_SEND') prevents an email from being sent when a critical attribute is missing. Synapse uses the required modifier:

Legacy: {{EventAttribute['Reference Number']|default('MOE_NOT_SEND')}}
Synapse: `{the Reference Number from the trigger event, required}`

When required resolves to null, the entire email is suppressed. The email_logs record is created with status: "suppressed" and the suppressed_reason field explains which attribute was missing.

Tip

Use the NLT Jinja2 migration tool to automatically convert existing Jinja2 templates to NLT syntax. The converter handles default('MOE_NOT_SEND') to required mapping automatically.


API Migration

Event Ingestion

Legacy API:

bash
curl -X POST https://api.legacy-cep.example.com/v1/event/YOUR_APP_ID \
-H "Content-Type: application/json" \
-H "MOE-APPKEY: YOUR_APP_KEY" \
-d '{
"type": "event",
"customer_id": "user_12345",
"actions": [{
"action": "wics_open",
"attributes": {"Reference Number": "WIC-2026-0001"},
"platform": "web"
}]
}'

Synapse:

bash
curl -X POST https://synapse-api.pyrx.tech/v1/events \
-H "Content-Type: application/json" \
-H "X-WORKSPACE-ID: ws_k7x9m2p4" \
-H "X-API-KEY: psk_live_..." \
-d '{
"event_name": "wics_open",
"external_id": "user_12345",
"attributes": {"reference_number": "WIC-2026-0001"},
"idempotency_key": "wics_open_WIC-2026-0001"
}'

Key Differences

ConcernLegacy CEPSynapse
AuthenticationMOE-APPKEY headerX-WORKSPACE-ID + X-API-KEY headers
User ID fieldcustomer_idexternal_id
Event formatNested actions arrayFlat event object
Attribute keysTitle Casesnake_case (NLT resolves both)
IdempotencyNot built-inidempotency_key field with 7-day TTL
ResponseSync (200 OK)Async (202 Accepted)

Flow Migration

Legacy Flow Structure

Trigger: Event "wics_open"
-> Filter: EventAttribute['claim_type'] == 'work_injury'
-> Action: Send Email (template: WICS Open Notification)
-> Wait: 24 hours
-> Condition: Has event "wics_submitted"?
-> Yes: Exit
-> No: Send Email (template: WICS Open Reminder)

Synapse Flow Configuration

json
{
"name": "WICS Open",
"trigger_event": "wics_open",
"trigger_conditions": {"claim_type": "work_injury"},
"content_type": "transactional",
"steps": [
{"type": "send_email", "template_slug": "wics-open-notification"},
{"type": "wait", "duration": "24h"},
{
"type": "condition",
"check": {
"source": "latest_event",
"event_name": "wics_submitted",
"exists": true
},
"on_true": "skip_to_end",
"on_false": "continue"
},
{"type": "send_email", "template_slug": "wics-open-reminder"}
]
}

Migration Checklist

  1. Export legacy templates -- Download all active template HTML and note the Jinja2 expressions used
  2. Convert Jinja2 to NLT -- Use the converter tool or manually translate using the syntax mapping above
  3. Map event names -- Align your legacy event names with the Synapse snake_case convention
  4. Map user attributes -- Ensure contact properties in Synapse include all attributes your templates reference
  5. Create templates -- Import converted HTML into Synapse via POST /v1/templates
  6. Create flows -- Recreate each legacy flow as a Synapse flow with the appropriate trigger, conditions, and steps
  7. Shadow mode -- Enable shadow mode (PYRXCRM_SHADOW_MODE=true) to log emails without sending, while your legacy platform continues as the primary sender
  8. Validate -- Compare Synapse email logs against legacy platform delivery for a sample period
  9. Cutover -- Disable legacy flows and activate Synapse flows
Warning

Run both systems in parallel during migration. Use shadow mode to verify Synapse produces the same output as your legacy platform before switching over.