Schema-First  ·  Engine Agnostic  ·  Dynamic Branching

Orchestrate complex
user journeys
through simple schemas.

Waymark decouples journey logic from your frontend and backend code. Define states, transitions, and conditions in structured JSON or YAML — and let the engine handle the rest.

journey.json
{
  "name": "Enterprise Onboarding",
  "nodes": [
    { "id": "11111111-1111-1111-1111-111111111111", "key": "user-type", "type": "Form", "isStartNode": true },
    { "id": "22222222-2222-2222-2222-222222222222", "key": "admin-setup", "type": "Form" },
    { "id": "33333333-3333-3333-3333-333333333333", "key": "guest-welcome", "type": "Information" }
  ],
  "connections": [
    {
      "sourceNodeId": "11111111-1111-1111-1111-111111111111",
      "targetNodeId": "22222222-2222-2222-2222-222222222222",
      "conditionField": "Role",
      "conditionOperator": "Equals",
      "conditionValue": "Admin"
    },
    {
      "sourceNodeId": "11111111-1111-1111-1111-111111111111",
      "targetNodeId": "33333333-3333-3333-3333-333333333333"
    }
  ]
}

Journey Orchestration in Action

Watch how Waymark dynamically routes users through conditional paths

User Type Form

isStartNode: true

Role = ?

Admin KYC Flow

Full compliance

Guest Welcome

Lightweight intro

if Admin
else Guest
0
Code Deploys Needed
Journey Variants
12
Condition Operators
100%
Runtime Evaluation

The Problem

Hardcoded logic is a maintenance nightmare

Every new journey variation means another PR, another deployment, and another round of regression testing. Conditional branches multiply. Business rules bleed into UI code. Engineers become gatekeepers for what should be product decisions.

// ❌ Before Waymark if (user.role === "admin") { showStep("admin-setup") } else if (user.country === "USA") { showStep("us-tax-form") } else if (plan === "enterprise" && revenue > 1_000_000) { showStep("kyc-full") } else { showStep("guest-welcome") }

The Solution

Declare journeys as data, not code

Waymark evaluates your JSON schema at runtime, resolving the next node for each session based on submitted data and customer profiles. Change journeys without touching source code — no build, no deploy, no rollback risk.

// ✅ With Waymark { "conditionField": "Role", "conditionOperator": "Equals", "conditionValue": "Admin", "priority": 0 } // The engine handles the rest. // No deployments required.

Everything you need to build dynamic journeys

From simple onboarding flows to complex compliance pipelines — Waymark provides the primitives to model any journey.

Schema-First Design

Define states, transitions, and conditions in JSON or YAML. The engine interprets your schema at runtime — no compilation required.

Engine Agnostic

Integrate via REST API from any platform — React, Vue, React Native, Node.js, or any HTTP client. The engine lives on the backend.

Dynamic Branching

12 condition operators (Equals, GreaterThan, MatchesRegex, …) evaluated against submitted payload or customer profile fields.

Compliance Rules

Attach server-side validation to any node via complianceRuleJson. Required fields, regex patterns, numeric ranges, and cross-field comparisons.

Document Upload

Built-in DocumentUpload node type with file type filtering, size limits, and progress streaming via SSE.

Webhooks & SSE

Real-time events for step-advanced, session-completed, and session-abandoned. Integrate downstream systems without polling.

Visual Journey Builder

Drag-and-drop admin UI at /admin/journey-builder. Design flows visually — drag nodes, draw connections, edit properties — without writing JSON.

How Waymark works

A journey is a directed graph stored as data. The engine evaluates it at runtime for each session.

STEP 1

Define your Flow

POST a JSON document describing nodes (Form, DocumentUpload, Redirect, Information, Logic) and their conditional connections to POST /api/flows.

STEP 2

Start a Session

Call POST /api/workflow/sessions/start with a flowId and optional customerProfileId. The engine returns the first node definition.

STEP 3

Render & Submit Steps

Your frontend renders the node using its type and jsonContent. On submit, the engine validates compliance rules and resolves the next node.

STEP 4

Completion & Webhooks

When no connection matches, the session is marked Completed. Registered webhooks fire immediately and retry on transient failure.

Session lifecycle

StartSession ──► Started
                    │
           SubmitStep (compliance pass)
                    │
          ┌─────────▼──────────┐
          │  Logic auto-advance │
          └─────────┬──────────┘
                    │
        ┌───────────┼────────────┐
        │           │            │
   next node    no next node  failOnError
   resolved     resolved      triggered
        │           │            │
     Started    Completed      Error
        │
   AbandonSession
        │
    Abandoned

Real-world use cases

Any multi-step, conditional user flow maps naturally onto a Waymark schema.

🏢

Enterprise Onboarding

Admin users see a full KYC flow; guest users are directed to a lightweight welcome sequence. Compliance questionnaires adapt to business size and region.

Form DocumentUpload Logic
💳

Payment Checkout

Route customers to credit card validation or PayPal based on their selection. Cross-field compliance rules enforce amount limits per payment method.

Branching Compliance Webhooks
🩺

Healthcare Intake

Patient intake forms that branch by insurance type, skip irrelevant sections, and route to external EHR systems via HttpCallback Logic nodes.

Redirect HttpCallback SSE

Code examples

From a simple contact form to a conditional payment flow — all expressed as data.

contact-form.json — 3-step Contact Form
{
  "name": "Contact Form",
  "nodes": [
    {
      "id": "11111111-1111-1111-1111-111111111111",
      "key": "personal-info",
      "type": "Form",
      "title": "Your details",
      "isStartNode": true,
      "jsonContent": "{\"fields\":[{\"name\":\"Name\",\"type\":\"text\",\"required\":true},{\"name\":\"Email\",\"type\":\"email\",\"required\":true}]}"
    },
    {
      "id": "22222222-2222-2222-2222-222222222222",
      "key": "message",
      "type": "Form",
      "title": "Your message",
      "jsonContent": "{\"fields\":[{\"name\":\"Subject\",\"type\":\"text\",\"required\":true},{\"name\":\"Body\",\"type\":\"textarea\",\"required\":true}]}"
    },
    {
      "id": "33333333-3333-3333-3333-333333333333",
      "key": "confirmation",
      "type": "Information",
      "title": "Thank you! We'll be in touch within 24 hours."
    }
  ],
  "connections": [
    { "sourceNodeId": "11111111-1111-1111-1111-111111111111", "targetNodeId": "22222222-2222-2222-2222-222222222222" },
    { "sourceNodeId": "22222222-2222-2222-2222-222222222222",       "targetNodeId": "33333333-3333-3333-3333-333333333333" }
  ]
}

Node type reference

Five built-in node types cover the full spectrum of journey interactions.

Type Description Key jsonContent fields
Form Renders a dynamic form from a field list. Supports text, email, number, select, checkbox, textarea, date. fields[] — name, type, required, options
DocumentUpload Renders a file picker with type and size enforcement. Files uploaded before step submission. acceptedFileTypes, maxFiles
Redirect Navigates to an external URL. Supports {{token}} interpolation for sessionId, flowId, customer fields. url — supports tokens
Information Displays a message with no submission required. The node title carries the display text. — (title field on node)
Logic Executes a server-side action automatically. Auto-advances through up to 20 consecutive Logic nodes. action, field, value, failOnError

Ready to orchestrate your first journey?

Start with the documentation — set up the engine in minutes with Docker and the .NET 10 SDK.