Journeys
A journey is a multi-step automation: a graph of trigger, wait, branch and send steps a contact moves through over time. It's the same category as ActiveCampaign or Klaviyo's flow builder. The one real difference is the send step — it mails one of your actual interactive email projects, so a welcome series can include a real poll or a scored quiz instead of static copy.
Triggers
A journey enrolls a contact when one of these happens:
- List joined — a contact is added to a specific list (CSV import, API push, or signup form).
- Form submitted — a specific signup form is submitted.
- Segment entered — a contact starts matching a saved segment.
- Date field — an anniversary/birthday-style trigger anchored to a contact field, recurring every year.
- Interaction — a specific block (or any block) fires a poll vote, form submit, RSVP, or similar.
- Purchase — a product-block checkout completes.
- Checkout abandoned — a Buy Now checkout on one of your own Product block emails was started but never completed, after a delay you set (minimum 5 minutes). This is the own-checkout path: no Shopify or WooCommerce connection required.
- Cart abandoned — a connected Shopify or WooCommerce store reports a cart that was started and left, looking back up to 30 days. This is the external-store path.
Cart vs. Checkout — Intent Split: Both triggers can run as separate journeys on the same account. Use checkout abandoned to target friction in your own in-email checkout (FAQs, trust signals, a countdown discount); use cart abandoned to catch a stall in a connected external store's own shopping cart. The
stagefield on each abandonment record tracks which kind it is, so analytics and webhooks correctly attribute each event.
- API — your own backend enrolls one of its contacts by calling
POST /api/v1/journeys/<id>/triggerwith{ email, listId }, using the same bearer API key as the Send API — for events MailInApp has no way to see on its own.
Steps
Build the graph visually on the canvas. The core steps are send (mail an interactive project), wait (a fixed delay, or "each contact's own best hour" — see send-time optimization), and branch (split on a condition, reusing the same audience-filter builder segments use). Beyond those three you also get split (a weighted A/B fork instead of a condition), update field, add/remove from list, webhook, and create ticket. A goal step exits the run early once a condition is met (stop an abandoned-cart journey the moment the contact pays, for instance), and exit ends it outright.
Branch and update-field steps can read either a contact field or the value from whatever interaction enrolled the run. A "send poll → branch on which option they picked" flow needs no field created up front.
There's no dry-run or simulate mode. The only safeguard before a journey goes live is that it always starts paused, so you review the whole graph and its content before switching it on. A step reached twice in the same run — a real branch rejoin, or a loop back to an earlier wait — collapses on the canvas into a "continues at" marker instead of being drawn twice. A genuine graph stays readable that way, rather than turning into an unreadable tree.
Safety rails
- Quiet hours hold a due send until the next allowed hour, checked against one timezone you set for the whole journey (not a per-contact field) — every enrolled contact shares the same quiet window.
- A per-contact, per-journey cap of 3 sends a day defers rather than drops an over-limit send until the next day.
- Auto-disable after 3 failed ticks in a row — a journey whose sends have all failed across a whole processing cycle turns itself off rather than silently burning through your list, the same protection recurring schedules already have.
Plans
Free includes 1 journey with up to 5 steps; every paid tier raises both caps — see pricing for the full table. A journey starts paused when created, so you can review the whole graph before turning it on.