Webhook-received enrollment vs event enrollment: external system pushes you in vs user fires a behavior event

Webhook vs behavior-event enrollment: signal source, identity, comparison table, ecommerce/SaaS examples, Leadara mapping, FAQ.

Sara Moradi

Designs customer journeys and marketing automation campaigns for retention and lower churn.

September 25, 2026 · 6 min read

Also available in فارسی

ورود به جرنی با وب‌هوک در برابر ورود با رویداد رفتار: هل سیستم خارجی در برابر سیگنال خود کاربر

Webhook-received enrollment starts a journey when an external system POSTs a payload that maps to an existing profile; event enrollment starts when that profile itself fires a tracked behavior after the workflow is live.

What is the difference between webhook-received enrollment and event enrollment?

Both put someone into a journey, but the signal source differs. With webhook-received enrollment, the push comes from outside: sales CRM, payment gateway, warehouse ERP, or support desk POSTs over HTTP; your MA maps the payload to a profile and fires enrollment. With event enrollment, the signal is the user’s own tracked behavior: product_viewed, cart_updated, lesson_completed—the stream that exists after go-live.

Mix them up and you either message before the user did anything real, or wait forever for a client event that never arrives because the system of record lives elsewhere.

How does each mode work?

Webhook-received enrollment

  1. An external system records a fact in its world (invoice issued, shipment created).
  2. It POSTs to your webhook endpoint with customer id and typed fields.
  3. Ingest resolves or creates a profile via email/phone/external_id.
  4. If the workflow enrolls on that webhook/message type, the user enters—even with zero in-app clicks.

Event enrollment

  1. SDK, pixel, or event API emits user behavior into the stream.
  2. The workflow listens for that event name (plus optional filters).
  3. Enrollment usually happens only for matches after the flow is live—unless you explicitly backfill.
  4. Order and repeats matter; pair with policies like every event vs once within a window.
DimensionWebhook-receivedEvent enrollment
Signal sourceExternal system pushUser/client tracked behavior
SDK dependencyUsually lowUsually high
Timing vs go-liveCan push historical factsUsually future matches only
Identity riskBad external_id → wrong profileEvents without stable id vanish
Best forPayments, ERP, tickets, server-side order stateBrowse, cart, lessons, in-product clicks
Debug surfaceHTTP logs and retriesEvent names, payloads, stream order

Read this beside event-centric vs contact-centric automation: that post is stream-vs-person; this one is which signal starts the trip.

Concrete examples

Home-goods ecommerce — ERP shipped status

ERP flips status to shipped and webhooks. The “after ship” journey must enroll on the webhook, not hope the shopper opens tracking. tracking_page_viewed is fine for later nurture, not for starting the ship path.

EdTech SaaS — gateway payment

Gateway sends payment_succeeded. That should enroll paid onboarding. first_lesson_started is a later branch, not the first enroll. Otherwise payers see silence until they open a lesson.

Support — P1 ticket from helpdesk

Helpdesk webhooks P1 to start a calm-down SMS/email journey. In-app behavior may be zero; the ticket system is the truth.

When to choose which

  1. Truth lives in another system → webhook.
  2. Truth is behavior you track in your product → event.
  3. If you have both, enroll on the system of record; use the other signal for branches/waits—not duplicate enrolls.
  4. Existing-at-activation backfill is a separate policy: see enroll existing at activation vs future-only.
  5. Do not confuse absence triggers with webhooks; see has-not filter trigger vs event trigger.

Leadara mapping (events, segments, journeys, email/SMS)

  • Events: keep stable behavior names; normalize inbound webhooks into consistent event names when possible.
  • Journeys: pick enrollment explicitly—webhook/system message vs user behavior event.
  • Segments: helper filters (VIP, region)—not a substitute for the enrollment source.
  • Email / SMS: operational webhooks → short SMS + detail email; exploratory in-product events → richer email.

Common mistakes

  • Enrolling on page_view for an ERP-only fact.
  • Webhooks without idempotency → retry = re-enroll.
  • Mapping empty-email payloads onto a shared guest profile.
  • Assuming webhooks are instant; queues add delay.
  • Double enrollment from payment webhook and client order_completed without re-entry guards.
  • Happy-path-only tests; simulate missing external_id.

One-line takeaway

Webhook = external system push onto a resolved profile; behavior event = the profile fires a tracked signal after the flow is live.

Next step

Open a journey that enrolls “late” or “never.” Write: where is the system of record—external server or user client? Enroll on that; move the other signal to a branch.

FAQ

Webhook and event arrive almost together?

Make one the enroll source; use the other for branch/wait only.

Webhook for a brand-new user with no profile?

Resolve/create identity first; orphan enrollments poison reports.

Can we replay history via webhook?

Technically yes; product-wise decide if old users should get today’s creative.

OTP / bank transactional?

Keep sensitive transactional sends out of nurture graphs. Payment webhook can start onboarding; OTP should not live in that same marketing journey.

vs has-not triggers?

Has-not enrolls on absence; webhook enrolls on arrival of an external signal.

Webhook received but no enroll?

Check ingest logs, profile resolve, then enrollment filters—often the segment filter fails after resolve.

SMS from ship webhook, email from tracking pageview?

Yes—tie channel to signal. Ship = SMS; later engagement = deeper email.

Step-by-step for growth

  1. State the start fact in plain language.
  2. Name the owner: product, finance, warehouse, support.
  3. External owner → webhook contract (fields, retry, signature).
  4. In-app owner → lock event name + filters in Leadara.
  5. Test ten profiles: duplicate webhooks, empty fields, events without ids.
  6. Watch “enrolled but no send” for a week—usually a silent filter.

Programmer-shaped sketch

on inbound_webhook(payload):
  profile = resolve(payload.external_id | email | phone)
  if profile and matches(enrollment_filters):
    enroll(journey, profile, source="webhook")

on behavior_event(name, profile):
  if journey.live and name in trigger_events and matches(filters):
    enroll(journey, profile, source="event")

Guards: webhook idempotency key; stable event names; one primary enroll source.

Metrics

  • Webhook→profile resolve rate
  • Time from webhook to first send
  • Share of enrolls by source (must match design)
  • Duplicate enrolls within 24h

PM language

Say “enrollment was on page_view; shipped truth is in ERP—switch to webhook,” not “automation is broken.”

Acceptance tests

  1. Replay the same webhook twice with one idempotency key → single enrollment.
  2. Webhook with unknown external_id → resolve/create path behaves as designed (no silent guest pile-up).
  3. Behavior event before journey go-live → should not enroll (unless backfill is on).
  4. Payment webhook enrolls; later first_lesson_started only branches—does not open a second parallel trip.
  5. Delayed webhook (queue 15 minutes) still maps to the correct profile and creative version.

Versus “has not done” enrollment

Absence triggers watch for missing behavior; webhooks watch for an external arrival. If your ERP never posts, a has-not trigger will not save you—you need monitoring on the webhook pipe itself.

Keep reading