Skip to main content

Call Flows - Complete Guide

Complete guide to building and managing Call Flows in Moja.

D
Written by Denise Abdullah

Call Flows - Complete Guide

For: Network Operators | Advertisers with Complex Routing Needs

Time: ~30 minutes to build your first Call Flow

Last Updated: March 27, 2026

What You'll Accomplish

By the end of this guide, you'll understand how to build sophisticated, event-driven call routing using Moja's visual Call Flow builder. You'll learn when to use Call Flows (versus simple Routing Plans), how to leverage different node types for conditional logic, and how to integrate with webhooks for data-driven routing decisions.

Table of Contents

What Are Call Flows?

Before You Build Your First Call Flow

When to Use Call Flows (vs. Simple Routing Plans)

The Visual Call Flow Builder

Understanding Node Types

Step-by-Step: Creating Your First Call Flow

Step-by-Step: Building Conditional Routing

Connecting Call Flows to Campaigns

Testing and Debugging Call Flows

Common Call Flow Patterns

Troubleshooting

Migration Guides

Frequently Asked Questions (FAQ)

What's Next?

What Are Call Flows?

Call Flows are Moja's visual, node-based builder for creating event-driven call routing logic. Think of Call Flows as a flowchart that executes in real-time as calls arrive—you can branch, make decisions, fetch data, tag calls, and route dynamically based on any combination of conditions.

The Difference: Routing Plans vs. Call Flows

In short:

Routing Plans are for straightforward routing (geo-based, time-based, round-robin)

Call Flows are for sophisticated, data-driven routing with conditional branching

Before You Build Your First Call Flow

Before diving into the Call Flow builder, understanding these foundational concepts will save you hours of troubleshooting and help you avoid common pitfalls.

Understanding the Moja Hierarchy

Call flows don't exist in isolation—they're part of a larger routing architecture. Here's how the pieces fit together:

Key Relationships:

Campaigns own Call Flows (one campaign = one Call Flow OR one Routing Plan, not both)

Incoming webhooks must be attached to the campaign to be available in Call Flows

Call Flows make routing decisions but ultimately point to Routing Plans

Routing Plans connect to Targets (your buyers/destinations)

Targets can be reused across multiple Routing Plans/campaigns

Real-world example:

⚠️ Important: Incoming webhooks must be attached to the campaign to make their data available in Call Flows. Navigate to your campaign settings → Incoming Webhooks section to verify the webhook is connected.

Tag Naming Best Practices

Tags are critical for reporting, filtering, and downstream logic. Inconsistent tag naming will break yomuur Call Flows. Establish naming conventions before building.

✅ DO: Use Consistent, Structured Naming

Naming rules:

Be consistent with casing — avoid mixing formats (e.g., don't use vip-customer in one place and VIP-Customer in another). Moja normalizes tags to UPPERCASE internally, so any casing will work, but consistent naming prevents confusion when reading your Call Flow configuration.

Hyphens or underscores for spaces — both high-value and high_value work. Underscores are easier for regex operations.

Descriptive prefixes — tier-vip not just vip (prevents collision)

No special characters except hyphens and underscores

Consistent abbreviations — If you use ca for California, don't also use calif or california

ℹ️ Note: Moja automatically normalizes custom tag names to UPPERCASE internally. So customer-tier, Customer-Tier, and CUSTOMER-TIER all resolve to the same tag. However, maintain lowercase naming in your documentation and processes for consistency.

Understanding System Tags vs. Custom Tags

System Tags are predefined by Moja and automatically populated (e.g., CALLER_ID, CALLER_STATE, CAMPAIGN_ID). These:

Do NOT need to be defined by you in the Custom Tags section

Are always available in Call Flows

Cannot be deleted or renamed

Custom Tags are created by you for your specific business logic (e.g., customer-tier, lead-score). These:

Must be predefined in Webhooks → Custom Tags before you can reference them in Call Flows

Can be set via incoming webhooks, Tagging nodes, or JavaScript nodes

Appear in reporting alongside system tags

Action: Before building Call Flows that use custom tags, navigate to Webhooks → Custom Tags and create your tag definitions there first.

❌ DON'T: Create Tag Chaos

Real-World Example: Fixing Tag Chaos

Before (broken logic):

// Your CRM sends different zip formats

// Call Flow tries to check zip code

if (tags.zip_code == "90210") { ... } // But the tag might be:

// zip, ZIP, zipcode, zip_code, ZipCode, caller_zip, caller-zip-code

After (clean, works every time):

// Standardize on ONE format: caller-zip

// Normalize in JavaScript node if needed

tags.CALLER_ZIP = tags.CALLER_ZIP || tags.ZIP_CODE || tags.ZIP || tags.ZIPCODE;

if (tags.CALLER_ZIP == "90210") { ... } // Always works

Action Items Before Building:

Document your tag taxonomy — Create a spreadsheet with approved tag names

Train your team — Everyone uses the same names

Validate incoming data — If publishers/webhooks send data, normalize it in a JavaScript node:

// Normalize zip code variations

tags.CALLER_ZIP = tags.CALLER_ZIP || tags.ZIP_CODE || tags.ZIP || tags.ZIPCODE;

RTB vs Static Routing: Decision Tree

💬 Customer Confusion: "Setting up RTB versus static publishers — the distinction isn't intuitive." — Cobras Solutions (Connor)

One of the most common questions: "Should I use RTB (Real-Time Bidding) or static routing?" The answer depends on your business model. Use this decision tree:

Static Routing Example (Simple)

Use case: You have 3 buyers. CA calls go to Buyer A ($50/call), TX calls go to Buyer B ($45/call), all others go to Buyer C ($40/call).

Pricing: Fixed, pre-negotiated per buyer.

RTB Example (Using RTB Groups)

Use case: You have 5 buyers who bid on each call. You want to maximize revenue by routing to the highest bidder.

Best Practice: Use Moja's built-in RTB Groups feature rather than building custom RTB logic in Call Flows.

Setup:

Create an RTB Group in RTB Groups section

Add your buyers to the group with bid parameters

In your Call Flow, route to a Routing Plan that uses the RTB Group

Why use RTB Groups instead of custom logic:

Built-in bid management and timeout handling

Automatic highest-bidder selection

Built-in analytics and reporting

Simpler to maintain than custom HTTP Request logic

Pricing: Dynamic—highest bidder wins. Could be $30 one call, $75 the next.

Key Difference:

Static: You control routing logic explicitly in Call Flow

RTB: Buyers control routing via bids; use RTB Groups for automatic handling

Most Common Setup: Hybrid — Use RTB Groups for high-volume campaigns, static routing for premium/exclusive buyers.

Common Pitfalls to Avoid

Before you start building, be aware of these traps that catch most first-time Call Flow builders:

⚠️ Pitfall 1: Tag Naming Inconsistency Breaking Logic

The Trap: Different parts of your system use different tag names for the same concept.

Example of Failure:

// Your webhook sends: caller_zip = "90210"

// Your Call Flow checks: if (tags.ZIP_CODE == "90210") { ... } ← NEVER MATCHES

// Your reporting filters by: ZipCode = "90210" ← NEVER FINDS DATA

Solution: Establish a single source of truth for tag names. Document it. Enforce it.

Action Items:

Create a "Tag Dictionary" spreadsheet

Share with your team, publishers, webhook developers

Add validation in Call Flows:

// Normalize all zip code variations to ONE tag

tags.CALLER_ZIP = tags.CALLER_ZIP || tags.ZIP_CODE || tags.ZIP || tags.ZIPCODE;

⚠️ Pitfall 2: Forgetting Fallback Paths

The Trap: Building Call Flows that assume data will always be available.

Example of Failure:

Problem: What if the webhook never arrives? customer_tier is null → matches FALSE path → routes to standard queue. VIP customers might get standard service if webhook is delayed.

Better Design:

Key Lesson: Always design for missing/bad data. Every If Statement should handle both TRUE and FALSE paths gracefully.

When to Use Call Flows (vs. Simple Routing Plans)

Use Call Flows When You Need To:

✅ Make routing decisions based on external data

Example: Wait for incoming webhook with customer tier, then route VIPs to priority agents

✅ Implement conditional branching logic

Example: If caller from California AND age > 65, route to Medicare specialist

✅ Fetch data from your systems mid-call

Example: HTTP request to your CRM to check customer status before routing

✅ Set custom tags dynamically during routing

Example: Tag calls as "high-value" if certain conditions are met

✅ Execute custom JavaScript logic

Example: Calculate a score based on multiple variables and route accordingly

✅ Wait for pre-call webhook data before routing

Example: Caller clicks an ad, your system sends data via webhook, then caller dials—Call Flow waits for that data

✅ Debug complex routing with visibility into each step

Example: Log variable values at each decision point to troubleshoot routing issues

Use Simple Routing Plans When:

❌ Your routing is straightforward (geo-based, time-based, round-robin)

❌ You don't need conditional branching

❌ You don't need to integrate with external systems

❌ Speed to implementation matters more than flexibility

💡 Tip: Start with a Routing Plan for your first campaign. When you outgrow it, migrate to a Call Flow. Moja makes it easy to switch execution modes in your Campaign settings.

The Visual Call Flow Builder

Accessing Call Flows

UI Path: Call flows (main sidebar)

Permissions: Admin and Member roles only

The Builder Interface

When you open the Call Flow builder, you'll see:

How It Works

Drag nodes from the sidebar onto the canvas

Connect nodes by dragging from one node's output handle to another node's input handle

Configure each node by clicking it and filling in the properties panel

Save your flow when complete

Attach to a Campaign to make it live

Visual flow structure:

Every Call Flow:

Starts automatically when a call arrives in a campaign using that Call Flow

Executes nodes sequentially following the connections you've drawn

Ends when a routing decision is made (Routing Plan node or Hangup node)

Understanding Node Types

Moja provides several node types, each with a specific purpose. Here's the complete reference:

Logic Nodes

If Statement

Color: Blue

Purpose: Conditional branching—split your flow based on whether a condition is true or false

When to use:

Route differently based on caller state/zip

Check if a variable meets a threshold

Branch based on webhook data or variable values

Configuration:

Variable A: Left side of comparison (use bracket syntax: [caller_state])

Operator: Comparison type (==, !=, <, >, <=, >=, ~= for regex)

Variable B: Right side of comparison (can be a static value or another bracketed variable)

Example:

Variable A: [customer_tier]

Operator: ==

Variable B: vip

Output paths:

TRUE: Condition matched—follow this path

FALSE: Condition not matched—follow this path

Best practices:

Use exact string matches for states: [CALLER_STATE] == "CA"

For numeric comparisons, use >, <, >=, <=

Chain multiple If Statement nodes for complex AND/OR logic

Use ~= for regex matching (Moja-specific syntax)

Always use bracket syntax for variable references: [variable_name]

Variable

Color: Teal

Purpose: Read, set, or manipulate variables during the call flow

When to use:

Store incoming webhook data in a reusable variable

Set a flag that later nodes can check

Read system tags like CALLER_ID, CALLER_STATE, CAMPAIGN_ID

Configuration:

Variable Name: Name of the variable to set or read

Variable Value: Value to assign (can reference other variables with [TAG_NAME])

Example use cases:

Read: customer_name from incoming webhook data

Set: routing_priority = high

Manipulate: Combine multiple values into one variable

Common system tags you can read:

[CALLER_ID] — Caller's phone number

[CALLER_STATE] — Caller's state (editable)

[CALLER_ZIP] — Caller's ZIP code (editable)

[CAMPAIGN_ID] — Campaign ID

[CAMPAIGN_NAME] — Campaign name

Custom data from incoming webhooks (use [custom_tag_name] syntax)

Tip: For the full list of 100+ available system tags, go to Webhooks → Custom Tags in the Moja portal. System tags are automatically available—you don't need to define them yourself.

Javascript

Color: Orange

Purpose: Execute custom JavaScript code during call flow execution

When to use:

Complex calculations or string manipulations

Multi-step logic that's cumbersome with multiple If Statement nodes

Advanced data transformations

How it works: The JavaScript node has access to two objects:

tags — All system tags and custom tags (read and modify)

variables — Custom variables set by other nodes

To set values that downstream nodes can use, modify these objects directly:

// Modify tags and variables objects directly

tags.GENDER = "Male";

variables.lead_score = 0;

// Read existing values and calculate

if (tags.CALLER_STATE == "CA") variables.lead_score += 10;

if (variables.customer_tier == "vip") variables.lead_score += 20;

// String manipulation

tags.CALLER_ID_FORMATTED = tags.CALLER_ID.replace("+1", "");

// Normalize tag variations

tags.CALLER_ZIP = tags.CALLER_ZIP || tags.ZIP_CODE || tags.ZIP || tags.ZIPCODE;

Tag Access in JavaScript:

System tags are automatically in UPPERCASE: tags.CALLER_STATE, tags.CAMPAIGN_ID

Custom tags are normalized to UPPERCASE: tags.CUSTOMER_TIER

Use tags.TAG_NAME syntax (not bracket syntax)

To reference tags in downstream If Statement nodes:

Use bracket syntax: [CALLER_STATE], [customer_tier]

Best practices:

Keep it simple—complex logic is harder to debug

Store results in tags or variables for downstream If Statement nodes

Test your JS separately before adding to Call Flow

Comment your code for future maintenance

Use tags for values you want to appear in call logs and reporting

Use variables for temporary calculation values

Capabilities:

fetch() is available for HTTP requests within JavaScript

Async/await supported

Standard JavaScript Math, String, Array, Date methods

Limitations:

Execution timeout: 5 seconds max

No require(), no file system access

For complex HTTP workflows, prefer the HTTP Request node

Data Nodes

Wait For Pre Call Webhooks

Color: Purple

Purpose: Pause call processing until incoming webhook data arrives (or timeout expires)

When to use:

You send caller data via incoming webhook before the caller dials

You need guaranteed data availability before making routing decisions

Pre-call enrichment from your CRM, database, or external systems

Configuration:

Wait Duration: Seconds to wait (configurable, no maximum limit)

How it works:

Caller clicks your ad or fills a form

Your system sends incoming webhook with caller data to Moja

Caller dials your Moja tracking number

Call Flow hits this node and waits up to X seconds

If webhook data arrives → flow continues immediately with data attached

If timeout expires → flow continues without webhook data (use If Statement to handle missing data)

Timing Diagram:

Example scenario:

practices:

Set timeout long enough for your webhook to arrive (typically 5-10 seconds)

Always have a fallback path for missing webhook data

Use Debug nodes after this to verify data arrived

Critical: Ensure incoming webhook is attached to the campaign (see "Before You Build" section)

⚠️ Important: The incoming webhook must be attached to the campaign for this node to access the data. Verify in campaign settings → Incoming Webhooks section.

📖 See the Webhooks Guide for detailed information on sending incoming webhook data to Moja.

HTTP Request

Color: Purple

Purpose: Make HTTP requests to external APIs during call flow execution

When to use:

Fetch data from your CRM mid-call

Send notifications to Slack or other services

Query external databases for routing decisions

Log call flow events to your analytics platform

Configuration:

Method: GET, POST, PUT, DELETE

URL: Endpoint to call (supports both HTTP and HTTPS)

Headers: Custom headers (for authentication, content-type)

Body: Request payload (for POST/PUT)

Response Variable: Store the Response Variable Name (usable in other nodes) and Response Body Variable Name (whole JSON string)

Example: Fetch customer data

Method: GET

Headers: {"Authorization": "Bearer YOUR_API_KEY"}

Store Response In: crm_data

Example: Send Slack notification

Method: POST

Headers: {"Content-Type": "application/json"}

Body: {"text": "VIP call incoming: [customer_name] | [CALLER_ID]"}

Best practices:

Keep requests fast (< 2 seconds response time)

Handle timeouts gracefully (don't block call routing)

Both HTTP and HTTPS endpoints are supported

Store responses in variables for use in downstream nodes

Test endpoints separately before adding to Call Flow

Limitations:

Request timeout: 10 seconds (hardcoded, not configurable)

If request fails or times out, variable is set to null and flow continues — always check for null before using response data

HTTP Response Format:

Successful responses stored as JSON object in two variables: responseVar (full HTTP response) and responseBodyVar (body only)

Access nested fields: [crm_data.account_status]

On any error (timeout, HTTP error, connection failure): variable set to null

Tagging

Color: Cyan

Purpose: Add or remove tags from the call

When to use:

Mark calls that meet certain criteria for filtering/reporting

Tag high-value calls for manual review

Apply labels based on routing decisions

Track which path through the Call Flow was taken

Configuration:

Action: Add or Remove tags

Tags: Comma-separated tag names

Example:

Action: Add

Tags: is-homeowner, high-value, premium-route

Use cases:

Tag calls routed to VIP agents as vip-call

Tag calls from specific states as california, texas

Tag calls that converted as converted (for reporting)

Remove tags that are no longer relevant: Action: Remove, Tags: new-lead

Best practices:

Use consistent naming conventions: lowercase, hyphens or underscores for spaces (underscores preferred for regex)

Don't over-tag—only tag what you'll filter/report on

Tags appear in call logs and are included in outgoing webhooks

Use tags to track A/B tests or routing experiments

Remember: Custom tags must be predefined in Webhooks → Custom Tags before use

ℹ️ Note: System tags (like CALLER_ID, CALLER_STATE) are automatically available and don't need to be defined. Custom tags you create must be predefined in the Custom Tags section before you can use them.

Routing Nodes

Routing Plan

Color: Pink

Purpose: Route the call to a specific Routing Plan (which in turn routes to Targets)

When to use:

Final routing decision in your Call Flow

You want to use an existing Routing Plan's logic (geo, capacity, etc.)

You need to route to multiple Targets with failover/priority logic

Configuration:

Routing Plan: Select from your existing Routing Plans

How it works:

Call Flow reaches this node

Call is handed to the selected Routing Plan

Routing Plan applies its rules (geo, capacity, schedule, etc.)

Call connects to a Target (buyer/destination)

Example:

About Call Transfers: There is no standalone "Transfer" node in Call Flows. Instead, transfers happen through this workflow:

Call Flow routes to a Routing Plan (using this node)

Routing Plan selects a Target

If the Target is configured as a SIP endpoint, the call is transferred via SIP

Best practices:

Create reusable Routing Plans for common destinations

Name Routing Plans clearly: "VIP Queue", "After-Hours Voicemail", "CA Medicare Agents"

Use Routing Plans for the final routing step (don't nest Call Flows and Routing Plans deeply)

💡 Tip: You can click "Create new" in the Routing Plan selector to create a Routing Plan on the fly while building your Call Flow.

Hangup

Color: Dark Red

Purpose: Immediately end the call

When to use:

Reject low-quality callers (e.g., blacklisted number)

Business is closed and no voicemail available

Caller didn't meet qualification criteria

Error state where routing isn't possible (e.g., HTTP request returned invalid response)

Configuration:

Reason: (Optional) Note why the call is being hung up (for logging)

Example use case:

Best practices:

Always log the reason for hanging up (helps with debugging)

Use sparingly—hanging up on callers hurts conversion rates

Consider routing to a message node instead (if you add that feature in the future)

Don't use for TCPA checks — TCPA filtering happens at the routing plan level, not in Call Flows

⚠️ Note: Compliance checks like TCPA screening should be configured at the routing plan or campaign level, not implemented as Hangup logic in Call Flows.

Utility Nodes

Debug

Color: Red

Purpose: Log variable and tag values for troubleshooting

When to use:

Testing new Call Flows

Troubleshooting why a condition isn't matching

Verifying webhook data is arriving correctly

Debugging variable values at specific points in the flow

Configuration:

Variables/Tags to Log: Comma-separated list using bracket syntax

Example:

Variables/Tags: [CALLER_STATE], [customer_tier], [crm_response]

How to use:

Add Debug nodes adjacent to key decision points in your flow (not in the direct flow path)

Save and test your Call Flow with a real call

Check the call log after the call completes

Debug logs show the exact values at that point in the flow

Best practices:

Place Debug nodes adjacent to If Statement nodes to see what's being compared — do not place them inline between the preceding node and the If Statement

Place Debug nodes adjacent to Variable nodes to verify data was read correctly

⚠️ Debug nodes should be branched off to the side, not in the direct flow of your routing logic

Remove or disable Debug nodes in production (they add log noise)

Always use bracket syntax: [variable_name] not variable_name

Always use bracket syntax: [variable_name] not variable_name

Output: Debug nodes write to the call log:

[Call Flow Debug] CALLER_STATE=CA, customer_tier=vip, crm_response={"status":"active"}

Step-by-Step: Creating Your First Call Flow

Let's build a simple Call Flow that routes calls based on the caller's state.

Business scenario:

Calls from California → Route to CA Agents

Calls from all other states → Route to National Agents

Before You Start

You have at least two Routing Plans created:

"CA Agents" (routes to California targets)

"National Agents" (routes to all other targets)

You know the UI path: Call flows (main sidebar)

You're logged in as Admin or Member role

Step 1: Navigate to Call Flows

Click Call flows in the main sidebar

You'll see the Call Flows listing page

Step 2: Create a New Call Flow

Click Create (top right)

You'll see the visual Call Flow builder

Step 3: Understand the Canvas

You'll see:

Canvas (center) — Empty canvas with a Start node

Node Sidebar (left) — Available node types

Toolbar (top) — Save, zoom, layout controls

Step 4: Add an If Statement Node

Find If Statement in the sidebar (blue)

Drag it onto the canvas

The Start node will automatically connect to your If Statement node

Step 5: Configure the If Statement

Click the If Statement node to select it

A configuration dialog will appear

Fill in the fields:

Name: "Check if California"

Variable A: [CALLER_STATE]

Operator: ==

Variable B: CA

Save the node configuration

Step 6: Add Routing Plan Nodes

Now we'll add two Routing Plan nodes—one for each outcome (TRUE/FALSE).

For the TRUE path (California):

Drag Routing Plan node onto the canvas

Position it to the right of the If Statement node, slightly above

Click to configure:

Routing Plan: Select "CA Agents" from the dropdown

Save the node configuration

For the FALSE path (Not California):

Drag another Routing Plan node onto the canvas

Position it below the first Routing Plan node

Click to configure:

Routing Plan: Select "National Agents"

Save the node configuration

Step 7: Connect the Nodes

Find the TRUE output handle on the If Statement node (usually the top output)

Click and drag from that handle to the input handle of the "CA Agents" Routing Plan node

Find the FALSE output handle on the If Statement node

Drag it to the input handle of the "National Agents" Routing Plan node

Your flow now looks like:

Step 8: Save Your Call Flow

Click Save in the top toolbar

Give your Call Flow a name: "Geographic Routing - CA vs National"

Click Create

Success! You've created your first Call Flow.

Step 9: Test Before Going Live (Optional)

Before attaching this to a campaign, you can test it:

Use the Debug node technique (see "Testing and Debugging" section)

Or attach it to a test campaign and make a test call

Verify It Worked

After attaching to a campaign and making test calls:

Navigate to Reporting or Call Tracking

Find your test calls

Check the Routing Path field—it should show which branch was taken

Calls from CA numbers should route to CA Agents

All other calls should route to National Agents

Step-by-Step: Building Conditional Routing

Now let's build a more sophisticated Call Flow that combines incoming webhook data with conditional routing.

Business scenario: You run an insurance lead generation campaign. You want to:

Wait for incoming webhook data with customer information

Route VIP customers to senior agents

Route active customers to standard queue

Route new leads to a qualification IVR first

Tag high-value calls for manual review

Before You Start

You've set up an incoming webhook (see Webhooks Guide)

Critical: Incoming webhook is attached to your campaign (Campaign settings → Incoming Webhooks)

Your webhook sends: customer_tier (values: "vip", "active", "new")

Custom tag customer_tier is predefined in Webhooks → Custom Tags

You have three Routing Plans:

"Senior Agents"

"Standard Queue"

"New Lead"

You've created your first Call Flow (follow the previous section)

Step 1: Create a New Call Flow

Navigate to Call flows

Click Create

You'll see the blank canvas with a Start node

Step 2: Add a Wait For Pre Call Webhooks Node

Drag Wait For Pre Call Webhooks from the sidebar (purple)

Connect the Start node to this node

Click the node to configure:

Name: "Wait for Customer Data"

Wait Duration: 5 seconds

Save the node configuration

Why this matters: This ensures your incoming webhook data has time to arrive before routing decisions are made.

Step 3: Add a Variable Node to Read Webhook Data

Drag Variable node onto the canvas (teal)

Connect the Wait node to this Variable node

Click to configure:

Variable Name: customer_tier

Variable Value: [customer_tier] (reads from incoming webhook)

Save the node configuration

Step 4: Add Debug Node (Testing)

Let's add a Debug node to verify webhook data is arriving:

Drag Debug node onto the canvas (red)

Place it adjacent to the Variable node — do not connect it inline between Variable and If Statement

Click to configure:

Variables to Log: [customer_tier], [CALLER_ID], [CALLER_STATE]

Save the node configuration

💡 Tip: You can remove this Debug node later once you've verified it's working. Remember to use bracket syntax [variable] in Debug nodes.

Step 5: Add First If Statement (Check for VIP)

Drag If Statement node (blue)

Connect the Variable node to this If Statement (main flow path)

Click to configure:

Name: "Check if VIP"

Variable A: [customer_tier]

Operator: ==

Variable B: vip

Save the node configuration

Step 6: Add Tagging Node for VIP Path (TRUE)

Drag Tagging node onto canvas (cyan)

Position it in the TRUE path area

Click to configure:

Action: Add

Tags: vip-customer, high-priority

Save the node configuration

Step 7: Add Routing Plan for VIP (TRUE Path)

Drag Routing Plan node (pink)

Connect the Tagging node to this Routing Plan

Click to configure:

Routing Plan: Select "Senior Agents"

Save the node configuration

Step 8: Add Second If Statement (FALSE Path - Check for Active)

Now handle the FALSE path from the VIP check:

Drag another If Statement node

Connect the FALSE output of the first If Statement to this new If Statement

Click to configure:

Name: "Check if Active Customer"

Variable A: [customer_tier]

Operator: ==

Variable B: active

Save the node configuration

Step 9: Add Routing for Active Customers (TRUE)

Drag Routing Plan node

Connect the TRUE output of the "Active Customer" If Statement to this node

Click to configure:

Routing Plan: "Standard Queue"

Save the node configuration

Step 10: Add Routing for New Leads (FALSE)

Drag Routing Plan node

Connect the FALSE output of the "Active Customer" If Statement to this node

Click to configure:

Routing Plan: "New Lead"

Save the node configuration

Step 11: Review Your Complete Flow

Your Call Flow should now look like:

Step 12: Save Your Call Flow

Click Save in the toolbar

Name it: "Insurance Routing - VIP, Active, New"

Click Create

Verify It Worked

After attaching to a campaign and sending test incoming webhook data:

Send webhook with customer_tier: "vip"

Make a test call

Check call log: should route to Senior Agents

Should have tags: vip-customer, high-priority

Send webhook with customer_tier: "active"

Make a test call

Should route to Standard Queue

Send webhook with customer_tier: "new" (or any other value)

Make a test call

Should route to New Lead

Connecting Call Flows to Campaigns

Once you've built your Call Flow, you need to attach it to a Campaign for it to execute.

⚠️ Critical Prerequisite: If your Call Flow uses incoming webhooks, ensure the webhook is attached to the campaign before making test calls.

Step-by-Step: Attach Call Flow to Campaign

Step 1: Navigate to Your Campaign

Click Campaigns in the main sidebar

Select the campaign you want to use this Call Flow with

Click to open the campaign edit view

Step 2: Verify Incoming Webhook Attachment (If Applicable)

If your Call Flow uses the "Wait For Pre Call Webhooks" node:

Scroll to the Incoming Webhooks section in campaign settings

Verify your incoming webhook is listed and attached

If not attached, add it now

Why this matters: The Wait node can only access webhook data if the webhook is connected to the campaign.

Step 3: Change Execution Mode

Scroll to the Routing Configuration section

You'll see two radio buttons:

Routing Plan (default)

Call Flow

Select Call Flow

Step 4: Select Your Call Flow

A dropdown will appear: Call Flow

Click the dropdown

Select your Call Flow from the list (e.g., "Insurance Routing - VIP, Active, New")

Step 5: Save Campaign

Scroll to the bottom

Click Save Changes

Wait for the success notification: "Campaign updated successfully"

Verify It's Connected

Make a test call to a tracking number in that campaign

Navigate to Call Tracking or Reporting

Find the test call

Check the Routing Details—it should show your Call Flow was used

Switch Back to Routing Plan (If Needed)

To revert to a simple Routing Plan:

Edit the campaign

Change Execution Mode back to Routing Plan

Select your Routing Plan

Click Save Changes

💡 Tip: Campaigns are automatically active when created—no need to activate separately. If your Call Flow isn't executing, check that the campaign itself is active (Status checkbox).

Testing and Debugging Call Flows

Testing Call Flows is critical—routing mistakes cost money and hurt caller experience. Here's how to test effectively.

Strategy 1: Use Debug Nodes

Best for: Verifying variable values and flow paths

How:

Add Debug nodes at key decision points in your flow

Configure them to log the variables you're checking:

Variables: [CALLER_STATE], [customer_tier], [routing_decision]

Save your Call Flow

Attach to a test campaign

Make test calls

Navigate to Call Tracking or Reporting

Find your test call and view the Call Log

Look for debug output:

[Call Flow Debug] CALLER_STATE=CA, customer_tier=vip, routing_decision=senior_agents

Best practices:

Place Debug nodes adjacent to (not inline before) If Statement nodes to see what's being compared

Place Debug nodes adjacent to Variable nodes to verify data was read correctly

⚠️ Do not place Debug nodes in the direct flow path (e.g., Variable → Debug → If Statement). Branch them off as a separate connection.

Remove or disable Debug nodes in production (they add log noise)

Always use bracket syntax: [variable] not variable

Strategy 2: Test with Known Data

Best for: Verifying specific conditions

How:

Send test incoming webhooks with controlled data (use your webhook integration method)

Immediately call your tracking number from the same phone number

Verify the call routed as expected

Repeat with different data values to test each branch

Test matrix example:

Strategy 3: Trace Call Flow Execution

Best for: Understanding which path the call took

How:

Use Tagging nodes to mark which path was taken

Example

After test calls, filter by tags in Reporting

Verify the correct path was taken

Strategy 4: Test Edge Cases

Don't just test the happy path—test these scenarios:

Best practice: Always have a fallback path for unexpected data.

Common Testing Issues

Issue: Call Flow doesn't execute at all

Check:

Campaign is using Call Flow execution mode (not Routing Plan)

Correct Call Flow is selected in campaign settings

Campaign is Active (Status checkbox is checked)

Test call is going to a number in that campaign

If using webhooks: Incoming webhook is attached to campaign

Issue: Conditional logic not working as expected

Check:

Variable names use bracket syntax: [customer_tier] not customer_tier

String comparisons use exact values: "vip" not "VIP" (unless normalized)

Operator is correct: == for equality, not =

Debug nodes show the variable has the value you expect

Issue: Webhook data not available in Call Flow

Check:

Incoming webhook was sent before the call arrived

caller_id in webhook matches the calling number exactly (format: +15551234567)

Incoming webhook is attached to the campaign (most common issue)

Wait For Pre Call Webhooks node has sufficient timeout (5-10 seconds)

Check Webhooks → Incoming Requests to verify webhook was received

Issue: HTTP Request node failing

Check:

Endpoint URL is correct (HTTP or HTTPS both supported)

Endpoint responds within 10 seconds

Authentication headers are correct

Test the endpoint separately with curl or Postman

Check response variable in Debug node (may contain error message)

Common Call Flow Patterns

Here are proven Call Flow patterns you can adapt for your use cases.

Pattern 1: Geo-Routing by State

Scenario: Simple geographic routing—California callers go to one buyer, everyone else to another.

When to use: Your buyers have geographic preferences or state licenses.

Variations:

Multi-state routing: Chain If Statements for TX, FL, NY, etc.

Zip code routing: Use [CALLER_ZIP] instead of [CALLER_STATE]

Area code routing: Use regex on [CALLER_ID]: [CALLER_ID] ~= ^\+1415.* for San Francisco

Pattern 2: Quality Filtering via CRM Lookup

Scenario: Before routing, check if the caller is a known customer in your CRM. Route VIPs to premium buyer, unknowns to standard buyer.

When to use: You have a CRM/database with customer quality data and want to maximize revenue by routing high-value callers to buyers who pay more.

Best practices:

Keep CRM API response time < 2 seconds

Handle API timeouts gracefully (route to default buyer if CRM is down)

Cache frequently-accessed customer data

Pattern 3: Wait for Webhook Data, Then Route Based on Score

Scenario: Caller clicks your ad, your system sends enrichment data (credit score, age, zip, etc.) via webhook, then caller dials. Route based on that data.

Timeline:

Call Flow:

When to use: You have pre-call data (from ad click, form fill, etc.) that affects routing decisions and buyer payouts.

Best practices:

Set Wait timeout to 8-10 seconds if your enrichment API is slow

Always handle missing webhook data (timeout path)

Tag calls with the score/tier for reporting

Ensure incoming webhook is attached to campaign

Use HTTPS webhooks only

Pattern 4: VIP Customer Fast Lane

Scenario: Incoming webhook identifies VIP customers, route them to priority agents

Use when: You have customer LTV or tier data and want to prioritize high-value callers.

Pattern 5: State-Based Routing with Exceptions

Scenario: Route by state, but VIP customers from any state go to a special queue

Use when: You have both tier-based and geo-based routing logic.

Pattern 6: Pre-Call Qualification via External API

Scenario: Check caller's credit score from your API before routing

Use when: You need to qualify callers against external data before routing.

⚠️ Warning: Hanging up on callers can hurt conversion. Consider routing to a "call you back" message instead.

Pattern 7: Business Hours Routing

Scenario: Route to live agents during business hours, voicemail after hours

Note: Moja doesn't have a built-in call_hour system tag. Use a JavaScript node to get the current time:

Use when: You want time-based routing beyond what basic Routing Plans offer.

💡 Tip: Adjust the UTC offset for your timezone. For complex time logic (weekends, holidays), extend the JavaScript node.

Pattern 8: A/B Testing Routing Strategies

Scenario: Route 50% of calls to Strategy A, 50% to Strategy B

Use when: You want to test different routing approaches and measure performance.

Analysis: Filter reports by test-group-a and test-group-b tags to compare conversion rates.

Pattern 9: Multi-Criteria Routing with Scoring

Scenario: Calculate a lead score based on multiple factors, route accordingly

Use when: You have complex scoring logic that's easier to express in JavaScript than multiple If Statement nodes.

Pattern 10: Webhook Data Enrichment + HTTP Request Combo

Scenario: Wait for incoming webhook with basic data, then enrich with your API

Use when: You have a multi-stage data fetch (webhook provides ID, then fetch full profile).

Pattern 11: Fallback Routing When Data Missing

Scenario: Use webhook data if available, otherwise use basic geo routing

Use when: Webhook data may not always be available (e.g., caller didn't come from your landing page).

Troubleshooting

This section addresses the most common customer pain points and troubleshooting scenarios.

Problem: Call Flow Not Executing

Symptoms: Calls bypass your Call Flow and go straight to a default route (or fail)

Diagnostic steps:

Check campaign execution mode:

Navigate to your campaign

Verify Execution Mode is set to Call Flow (not Routing Plan)

Verify the correct Call Flow is selected

Check campaign status:

Ensure campaign Active checkbox is checked

Inactive campaigns don't process calls

Check tracking number assignment:

Verify the test call is going to a number assigned to this campaign

Navigate to Numbers and check campaign association

Check Call Flow saved state:

Open the Call Flow in the builder

Ensure there are no unsaved changes

Re-save if necessary

Check for disconnected nodes:

Every node (except end nodes) should have an outgoing connection

No orphaned nodes that can't be reached from Start

Check incoming webhook attachment (if applicable):

If your flow uses Wait For Pre Call Webhooks, verify the webhook is attached to the campaign

Campaign settings → Incoming Webhooks section

Problem: "Why Isn't My If Statement Working?"

Symptoms: Calls always go down the FALSE branch even when you expect TRUE

Diagnostic steps:

Check call log to see actual values

Check variable syntax:

Use brackets: [CALLER_STATE] not CALLER_STATE

Common mistake: Forgetting the brackets → variable name is treated as literal string

Example of broken logic:

Variable A: CALLER_STATE ← WRONG (missing brackets)

Operator: ==

Variable B: CA

This compares the string "CALLER_STATE" to "CA" → always FALSEFixed:Variable A: [CALLER_STATE] ← RIGHT (with brackets)

Operator: ==

Variable B: CA

Check for data type mismatches:

[CALLER_STATE] might be "CA" (string) not just CA

Use exact string matches: "CA" with quotes if needed

Check for case sensitivity:

While Moja normalizes tags to UPPERCASE internally, ensure your comparison values match

For custom variables, use consistent casing or normalize in JavaScript

Check for whitespace:

"vip " (with trailing space) ≠ "vip"

Use .trim() in JavaScript node if needed:

tags.CUSTOMER_TIER = tags.CUSTOMER_TIER.trim();

Check operator:

Use == for equality, not = (assignment)

Use != for not equal

Verify variable exists:

If Variable A doesn't exist, comparison may fail

Use Debug to confirm variable has a value

Problem: "Webhook Data Not Available"

Symptoms: Variables from incoming webhook are empty or null in Call Flow

Diagnostic steps:

Check incoming webhook timing:

Webhook must be sent before caller dials

If webhook arrives after call starts, Wait node may timeout

Verify webhook was received:

Navigate to Webhooks → Incoming Requests

Find your webhook request

Check status (should be 200/success)

Verify payload contains the expected data

Check caller_id format:

Webhook caller_id must match exactly: +15551234567

Common mistakes: missing +, different format

Check campaign attachment:

Most common issue: Incoming webhook must be attached to the campaign

Navigate to campaign → check Incoming Webhooks section

If not listed, attach it now

Increase Wait timeout:

Edit the Wait For Pre Call Webhooks node

Try 8-10 seconds instead of 5

Check webhook lifespan:

Default: 3600 seconds (1 hour)

If webhook was sent more than 1 hour ago, it's expired

Verify variable names:

If webhook sends customer_tier, read it as [customer_tier]

Variable names are case-insensitive but use consistent naming

Problem: "Calls Not Routing to Expected Buyer"

Symptoms: Calls route to wrong destination, or routing logic seems random. Where do Debug nodes belong?

Diagnostic steps:

Check Debug node placement strategy:

Adjacent to Variable nodes — Verify data was read (not inline in main flow)

Adjacent to If Statement nodes — See what's being compared (connect as a separate branch, not between nodes)

After HTTP Request nodes — Verify API response

After JavaScript nodes — Confirm calculations are correct

⚠️ Important: Debug nodes should NOT be placed in the direct flow path between nodes (e.g., Variable → Debug → If Statement). Instead, branch them off to the side so they don't interrupt your main routing logic.

Trace the execution path with tags:

Then filter call logs by tags to see which path was taken.

Check for missing FALSE paths:

Every If Statement should have both TRUE and FALSE connected

Missing FALSE path → call has nowhere to go → unpredictable behavior

Verify Routing Plan configuration:

Open the Routing Plan node

Confirm it's pointing to the correct Routing Plan

Check the Routing Plan itself has valid targets

Problem: "Tags Not Passing to Webhook"

Symptoms: Outgoing webhooks don't include expected tags, or tags have different names than expected

Root cause: Tag naming inconsistency between Call Flow, webhooks, and downstream systems

Diagnostic steps:

Verify tags are being set:

Add Debug node after Tagging node

Log all tags to confirm they're applied

Check tag naming consistency:

In Call Flow: caller-zip

In webhook payload: caller_zip or callerZip or zip?

In your system: zipcode or ZIP or zip_code?

These are all DIFFERENT tags. Pick one format and stick to it everywhere.

Standardize tag names:

Create a "Tag Dictionary" document

Use the same format everywhere: caller-zip (lowercase, hyphens)

Normalize incoming data in JavaScript node:

// Normalize all zip code variations to ONE tag

tags.CALLER_ZIP = tags.CALLER_ZIP || tags.ZIP_CODE || tags.ZIP || tags.ZIPCODE;

Check outgoing webhook configuration:

Navigate to Webhooks → Outgoing

Verify webhook is attached to the campaign

Check webhook payload template includes tags

Test with a webhook debugging tool:

Use webhook.site or similar

Send a test call

Inspect the exact payload your system receives

Compare tag names to what you expect

Problem: HTTP Request Node Failing

Symptoms: HTTP Request node returns errors or empty response

Diagnostic steps:

Test endpoint separately (optional for reference):

Verify endpoint is reachable and returns data using your preferred testing method

Check timeout:

Endpoint must respond within 10 seconds

Optimize your API or cache data if possible

Check authentication:

Verify headers are correct: {"Authorization": "Bearer YOUR_KEY"}

Check for typos in API keys

Check URL format:

Both HTTP and HTTPS are supported

Variable interpolation: [CALLER_ID] should be replaced automatically

Check response handling:

Use Debug node to log the response variable

Response may contain error messages (e.g., {"error": "Invalid API key"})

Check for SSL/certificate issues:

Ensure endpoint has valid SSL certificate (if using HTTPS)

Self-signed certs may be rejected

Problem: JavaScript Node Not Working

Symptoms: Variables set in JavaScript node are empty/wrong downstream

Diagnostic steps:

Test JavaScript separately:

Copy your JS code to a browser console or Node.js REPL

Test with sample data

Fix syntax errors

Check variable assignment:

Modify the tags and variables objects directly

Using var, let, or const for local calculations is fine — Moja reads from tags and variables when the node completes

Example:// ✅ CORRECT: Modify tags and variables objects

var score = 0; // local variable is fine

if (tags.CALLER_STATE == "CA") score += 10;

variables.lead_score = score; // This is what Moja reads

tags.PRIORITY = "high"; // Can also set tags

Check for runtime errors:

Add Debug node after JavaScript node

Log the variables you set using bracket syntax: [lead_score], [PRIORITY]

If empty, check for JS errors

Keep it simple:

Avoid complex logic that's hard to debug

Break into multiple nodes if needed

Check variable scope:

System tags are available via tags.TAG_NAME (e.g., tags.CALLER_STATE)

Custom variables are available via variables.name (e.g., variables.customer_tier)

Problem: Call Flow Hangs or Times Out

Symptoms: Calls get stuck and don't route

Diagnostic steps:

Check for infinite loops:

Ensure every path leads to a routing decision (Routing Plan or Hangup)

No circular connections between nodes

Check Wait node timeout:

If Wait For Pre Call Webhooks timeout is too high (> 10 seconds), calls may feel stuck

Reduce to 5 seconds

Check HTTP Request timeouts:

If external API is slow (> 10 seconds), request will timeout

Optimize API or handle timeouts gracefully

Check for missing connections:

Every If Statement should have both TRUE and FALSE paths connected

Missing connections = call has nowhere to go

Problem: Tags Not Appearing in Call Logs

Symptoms: Tagging nodes seem to execute, but tags don't show in reporting

Diagnostic steps:

Check tag syntax:

Tags should be lowercase, hyphen-separated or underscore separated: high-value or high_value, not High Value

No special characters except hyphens and underscores

Check Tagging node configuration:

Action should be Add (not Remove)

Tags field should not be empty

Check call completion:

Tags may not appear until call fully completes

Refresh the call log view

Check for Remove tags nodes:

If a downstream Tagging node removes the tag, it won't appear

Check custom tag definition:

Custom tags must be predefined in Webhooks → Custom Tags

System tags are automatically available

Migration Guides

Switching from another call tracking platform? These guides map common patterns from other platforms to Moja Call Flows.

Migrating from Ringba

Ringba users typically have these patterns:

Ringba Pattern → Moja Call Flow Equivalent

Common Ringba Tag Naming Issues

Problem: Ringba allows freeform tag names → inconsistency → broken logic

Solution in Moja:

Establish tag naming conventions before building flows (see "Before You Build" section)

Use JavaScript node to normalize incoming tags:

// Normalize all zip variations to ONE format

tags.CALLER_ZIP = tags.CALLER_ZIP || tags.ZIP_CODE || tags.ZIP || tags.ZIPCODE;

Ringba → Moja Migration Checklist

Export Ringba call logs to identify all tags used (create a Tag Dictionary)

Map Ringba IVR menus to Moja IVRs (separate feature) + Call Flow routing

Recreate routing rules as If Statement nodes

Convert Ringba "Number Pools" to Moja Dynamic Number Insertion (DNI)

Migrate webhook integrations (Ringba → Moja incoming/outgoing webhooks)

Test with parallel traffic (run both platforms simultaneously for 1-2 weeks)

Migrating from Retriever (Invoca)

Retriever/Invoca users typically have these patterns:

Retriever Pattern → Moja Call Flow Equivalent

Retriever → Moja Migration Checklist

Map Retriever "Campaigns" to Moja Campaigns (1:1 mapping)

Convert Retriever "Publisher" structure to Moja Publishers

Migrate Retriever "Buyer Connections" to Moja Targets

Recreate dynamic routing rules as Call Flows

Convert Retriever "Signal Tags" to Moja Tagging nodes

Migrate pre-call webhooks to Moja incoming webhooks

Migrate post-call webhooks to Moja outgoing webhooks

Test QAI transcription accuracy vs Retriever's transcription

Migrating from Invoca

Invoca users typically have these patterns:

Invoca Pattern → Moja Call Flow Equivalent

Invoca → Moja Migration Checklist

Export Invoca "Custom Data" fields → Map to Moja incoming webhook fields

Convert Invoca "Signal AI" rules to Moja QAI + Tagging nodes

Migrate Invoca "Routing Profiles" to Moja Call Flows

Recreate Invoca "Network Integrations" with HTTP Request nodes

Map Invoca "Destination Groups" to Moja Routing Plans

Test repeat caller detection logic

Migrate compliance settings (TCPA, DNC lists)

General Migration Best Practices

Run platforms in parallel for 1-2 weeks — Compare call routing accuracy

Start with one campaign — Don't migrate everything at once

Document your old platform's logic — Screenshot flows, export configs

Create a Tag Dictionary before migrating — Prevent naming inconsistency

Test edge cases — What happens when webhook is missing? API is down?

Train your team — Moja's visual builder is different from form-based routing

Leverage Moja support — Schedule migration planning call with your account manager

Frequently Asked Questions (FAQ)

General

Q: How many nodes can I add to a Call Flow?

A: There's no strict limit, but we recommend keeping flows under 20-30 nodes for performance and maintainability. If your flow is becoming very complex, consider breaking it into multiple Call Flows or using JavaScript nodes to consolidate logic.

Q: Can I reuse a Call Flow across multiple campaigns?

A: Yes! The same Call Flow can be selected in multiple campaigns. This is useful for common routing logic (e.g., "VIP Routing" applied to all your premium campaigns).

Q: Can I clone a Call Flow?

A: Not directly in the UI currently. Workaround: Open the Call Flow you want to clone, manually recreate the nodes in a new Call Flow, or contact support to request cloning.

Q: Can I export/import Call Flows?

A: Not currently supported. This is a planned feature—contact your account manager if this is critical for your workflow.

Execution & Performance

Q: How fast do Call Flows execute?

A: Most Call Flows execute in under 1 second. HTTP Request nodes and Wait For Pre Call Webhooks nodes add latency (5-10 seconds max). Design flows to minimize caller wait time.

Q: Do Call Flows execute in parallel or sequentially?

A: Sequentially. The call follows one path through the flow from Start to a routing decision. Nodes execute one after another in the order you've connected them.

Q: What happens if a node fails (e.g., HTTP request times out)?

A: The flow continues. Failed nodes typically set an error value in the response variable. Always design fallback paths for node failures.

Q: Can I pause or stop a Call Flow mid-execution?

A: No. Once a call enters a Call Flow, it executes to completion (Routing Plan or Hangup node). You can't interrupt mid-flow. Design your flows with explicit exit paths (Hangup nodes) if you need to terminate early.

Data & Variables

Q: What system tags are available?

A: Moja provides 100+ system tags you can use in call flows. Common examples:

[CALLER_ID] — Caller's phone number (+15551234567)

[CALLER_STATE] — Caller's state (editable)

[CALLER_ZIP] — Caller's ZIP code (editable)

[CAMPAIGN_ID] — Campaign identifier

[CAMPAIGN_NAME] — Campaign name

[BUYER_NAME] — Buyer name

[GCLID] — Google Click ID

[UTM_SOURCE] — UTM source from landing page

To view the full, current list: Go to Webhooks → Custom Tags in the Moja portal.

Note: System tags are automatically available and do not need to be defined by you. Custom tags you create must be predefined in the Custom Tags section before use.

Q: Can I set variables that persist across multiple calls from the same caller?

A: No. Variables are scoped to a single call. If you need cross-call persistence, use incoming webhooks to send caller context from your system on each call.

Q: Can I do math in If Statement conditions?

A: Not directly. Use a JavaScript node first to calculate the result, then use If Statement to check it:

Q: Are tags and variables case-sensitive?

A: Tags: Moja automatically normalizes custom tag names to UPPERCASE internally, so customer-tier, Customer-Tier, and CUSTOMER-TIER all resolve to the same tag. However, maintain lowercase naming in your documentation for consistency.

Variables: Case-insensitive comparisons are used internally.

Best practice: Use consistent naming conventions even though the system is case-insensitive.

Integration & Webhooks

Q: Can I use outgoing webhooks with Call Flows?

A: Yes! Outgoing webhooks are configured at the campaign level, not the Call Flow level. Attach outgoing webhooks to your campaign, and they'll fire for calls processed by that Call Flow.

Q: Can Call Flows trigger outgoing webhooks at specific points in the flow?

A: Use the HTTP Request node to POST to any endpoint (including your own webhook receivers). For Moja's built-in outgoing webhooks, they fire based on call events (e.g., "On Conversion"), not Call Flow nodes.

Q: What happens if the Wait For Pre Call Webhooks node times out?

A: The flow continues without webhook data. Downstream nodes that reference webhook variables will see empty/null values. Always design fallback paths for missing webhook data.

✅ Confirmed: The Wait node proceeds immediately when the webhook is received — it doesn't wait the full timeout duration. If the webhook doesn't arrive before timeout, the flow continues with empty values.

Q: Can I send data from a Call Flow back to my system?

A: Yes, use the HTTP Request node to POST data to your endpoint. Include call variables in the request body:

Method: POST

Body: {"caller_id": "[CALLER_ID]", "route_taken": "vip"}

Debugging & Testing

Q: Can I test a Call Flow without making an actual call?

A: Not directly. You must make a test call. Best practice: Use a dedicated test campaign and test tracking numbers to avoid polluting production data.

Q: How do I see which path a call took through a Call Flow?

A: Use Tagging nodes to mark each path:

If Statement TRUE → Tagging: Add "flow-path-a"

If Statement FALSE → Tagging: Add "flow-path-b"

Then filter call logs by tag.

Q: Can I see a visual representation of a call's flow after the call completes?

A: Not currently. This is a planned feature. Use Debug nodes and tags to trace execution for now.

Q: Debug nodes aren't logging anything. Why?

A: Check:

Debug node is connected in the flow

Call actually executed the flow (check campaign execution mode)

You're looking at the correct call log entry

Variables you're logging use bracket syntax: [variable_name]

Variables you're logging actually exist (typo in variable name?)

Advanced

Q: Can I nest Call Flows (call one Call Flow from another)?

A: Not directly. Call Flows are terminal—they execute to a routing decision. Workaround: Use Routing Plan nodes to add additional routing logic (Routing Plans can be chained).

Q: Can I use regex in If Statement conditions?

A: Yes, use the ~= operator:

Variable A: [CALLER_ID]

Operator: ~=

Variable B: ^\+1415.*

This checks if CALLER_ID starts with +1415 (San Francisco area code).

Q: Can I route to different campaigns from a Call Flow?

A: No. Call Flows route to Routing Plans within the same campaign. Routing Plans then route to Targets (which may belong to different buyers/campaigns indirectly). If you need cross-campaign routing, use Routing Plans with Targets assigned to multiple campaigns.

Q: Can I play custom audio messages in a Call Flow?

A: Not currently with a dedicated node. Workaround: Route to an IVR that plays the message, then transfers to the final destination.

Q: Can I transfer calls mid-flow?

A: There is no standalone "Transfer" node in Call Flows. Transfers happen through this workflow:

Route to a Routing Plan (using Routing Plan node)

Routing Plan selects a Target

If the Target is configured with a SIP endpoint, the call is transferred via SIP

Configure SIP transfer settings at the Target level, not in the Call Flow.

What's Next?

Now that you understand Call Flows, explore these related features to build even more powerful routing logic:

For Data-Driven Routing

Webhooks Guide — Send and receive real-time data to enrich Call Flows

Custom Tags — Create custom tags for advanced filtering and reporting (Webhooks → Custom Tags)

HTTP Integrations — Connect Call Flows to your CRM, databases, and external APIs

For Conversion Optimization

RTB Groups — Use built-in RTB Groups for Real-Time Bidding instead of custom logic

Conversion Rules — Define what qualifies as a conversion for your campaigns

For Advanced Routing

Routing Plans — Combine with Call Flows for sophisticated fallback/priority logic

Targets — Configure Targets with concurrency, caps, and schedules

Number Pools (DNI) — Dynamically assign tracking numbers for attribution

For Analytics & Reporting

Reporting Dashboard — Filter by tags and analyze Call Flow performance

QAI Analysis — Transcribe and analyze calls routed through Call Flows

Call Logs — Deep dive into individual call routing decisions

Need Help?

Support:

In-app chat: Click the support icon in the bottom right

Appendix: Quick Reference

Node Type Summary Table

Common Tag Reference

Full list: See Webhooks → Custom Tags in the Moja portal for all 100+ available system tags.

Remember: System tags are automatically available. Custom tags must be predefined before use.

Operator Reference (If Statement)

Variable Syntax Reference

In If Statement nodes:

Always use bracket syntax: [CALLER_STATE], [customer_tier]

In JavaScript nodes:

System tags: tags.CALLER_STATE (automatically UPPERCASE)

Custom tags: tags.CUSTOMER_TIER (normalized to UPPERCASE)

Variables: variables.lead_score

In Debug nodes:

Use bracket syntax: [CALLER_STATE], [lead_score]

Best practice: Be consistent. Use brackets [variable] in all node configuration fields.

Troubleshooting Checklist

When a Call Flow isn't working:

Campaign execution mode is set to Call Flow (not Routing Plan)

Correct Call Flow is selected in campaign settings

Campaign is Active (Status checkbox checked)

Call Flow has been Saved

All nodes are connected (no orphaned nodes)

Variable names use bracket syntax: [CALLER_STATE] not CALLER_STATE

If Statement operators are correct (== not =)

Incoming webhook attached to campaign (if using webhook data) ← Most common issue

Webhook caller_id format matches exactly

Wait For Pre Call Webhooks timeout is sufficient (5-10 sec)

HTTP Request endpoints respond within 10 seconds

Debug nodes added to verify variable values

Debug nodes use bracket syntax: [variable]

Test calls going to correct tracking number/campaign

Tag naming is consistent (lowercase, hyphens, no variations)

Custom tags predefined in Webhooks → Custom Tags

Did this answer your question?