Automation

Event-driven email sequences

Define steps, activate the journey, fire product events. Molted Email handles execution, branching, and per-contact run tracking. No cron jobs, no polling loops.

Diagram showing an event-driven email sequence with trigger, conditional branching, and policy-checked delivery steps

How it works

1

Create a journey

POST to /v1/journeys with a name and a trigger event (something like "user.signed_up" or "trial.ending").

2

Add steps

Four step types: send (email), delay (wait N minutes), branch (conditional routing), and end. Add them in order via POST /v1/journeys/:id/steps.

3

Flip it to active

PATCH /v1/journeys/:id with status "active". Inactive journeys ignore trigger events, so you can build and test before going live.

4

Fire events from your agent

POST to /v1/agent/events/ingest with an event name and contact email. If the event matches a journey trigger, a run spins up and the first step fires immediately.

5

Execution is automatic

Send steps go through the full policy engine (deduplication, rate limits, suppressions). Delay steps pause. Branch steps route based on contact fields. You don't manage any of this.

6

Per-contact run tracking

GET /v1/journeys/:id/runs shows active and completed runs. Duplicate runs for the same journey + contact are blocked automatically.

Build a journey

POST /v1/journeys + POST /v1/journeys/:id/steps

// 1. Create the journey
POST /v1/journeys
{
  "tenantId": "your-tenant-id",
  "name": "Onboarding Sequence",
  "triggerEvent": "user.signed_up"
}

// 2. Add a send step
POST /v1/journeys/:id/steps
{
  "tenantId": "your-tenant-id",
  "stepOrder": 1,
  "stepType": "send",
  "config": {
    "templateId": "onboarding-welcome",
    "dedupeKeyPrefix": "onboarding",
    "payload": { "trialDays": 14 }
  }
}

// 3. Add a delay step
POST /v1/journeys/:id/steps
{
  "tenantId": "your-tenant-id",
  "stepOrder": 2,
  "stepType": "delay",
  "config": { "delayMinutes": 1440 }
}

Step types

Send

Policy-checked email send. Template, dedupe key, dynamic payload. If policy blocks it, the run continues but the send is skipped.

Delay

Wait N minutes. Simple but essential for spacing out a welcome series or giving a trial user time to activate.

Branch

Conditional routing based on contact fields. Different paths for different segments, within the same journey.

End

Marks the run as complete. That's it. Contacts who reach this step are recorded as finished.

One event starts the whole sequence

Fire a product event and the matching journey kicks off. If a run already exists for that journey + contact, the duplicate is blocked.

POST /v1/agent/events/ingest
{
  "tenantId": "your-tenant-id",
  "eventName": "user.signed_up",
  "contactEmail": "alice@example.com",
  "payload": { "plan": "starter" }
}

Stop managing sequences by hand

Define the journey once. Events trigger it, policy governs every send, and you get per-contact tracking without building any of the plumbing.