Flow

Overview

The Flow in VoIPBIN is a powerful set of instructions that guides the platform on how to handle incoming calls. When someone calls one of your VoIPBIN numbers or destinations, the platform looks up the associated URL and sends a request. The Flow instructions are then read to determine the appropriate actions to be taken, such as recording the call, playing a message, or prompting the caller to press digits on their keypad.

At its core, the Flow is an array of JSON objects with special tags defined by VoIPBIN, enabling users to build their own Programmable Voice applications.

How the flow works

When an incoming call is received on one of your VoIPBIN numbers or destinations, the platform identifies the associated URL and sends a request.

The Flow instructions are then processed, providing a step-by-step guide on how to handle the call. This might involve greeting the caller, presenting options, gathering input, or executing various actions based on the caller’s response.

Understanding Flow Execution

Think of a Flow like a recipe. Each action is a step, and VoIPBIN follows the steps one by one until the recipe is complete.

The Execution Cursor

VoIPBIN uses a “cursor” to track where it is in the flow - like a finger pointing at the current step:

Flow Actions Array:
+---------+   +---------+   +---------+   +---------+   +---------+
| answer  |-->|  talk   |-->| digits  |-->| branch  |-->| hangup  |
+---------+   +---------+   +---------+   +---------+   +---------+
                   ^
                   |
                cursor
              (current step)

As each action completes, the cursor moves to the next one. When the cursor reaches the end, the flow is complete.

What Happens During Execution

+---------------------------------------------------------------------+
|                    Flow Execution Engine                            |
+---------------------------------------------------------------------+
                                |
                                v
                       +---------------+
                       |  Get next     |
                       |  action       |
                       +-------+-------+
                               |
                               v
                       +---------------+
                  +----|  End of flow? |----+
                  |yes +---------------+ no |
                  |                         |
                  v                         v
           +------------+          +----------------+
           |   Stop     |          | Execute action |
           |  (done)    |          +-------+--------+
           +------------+                  |
                                           v
                                +---------------------+
                                | What kind of result?|
                                +----------+----------+
                                           |
                    +----------------------+----------------------+
                    |                      |                      |
                    v                      v                      v
             +------------+         +------------+         +------------+
             |   Next     |         |   Wait     |         |   Block    |
             | (continue) |         | (external) |         |  (pause)   |
             +-----+------+         +------------+         +------------+
                   |
                   | loop back
                   +---------------------------------------------->

Action Execution Patterns

Actions behave differently depending on their type. Understanding these patterns helps you predict flow behavior.

Immediate Actions (Execute and Continue)

These actions complete instantly and the cursor moves to the next action:

+----------+     +----------+     +----------+
|  goto    |---->|  branch  |---->| variable |
+----------+     +----------+     +----------+
     |                |                |
     +----------------+----------------+
                      |
               Cursor moves immediately

Examples: goto, branch, variable_set, condition_variable

Media Actions (Wait for Completion)

These actions take time and the flow waits for them to finish:

+----------+     +------------------------------+     +----------+
|  talk    |---->|  Playing "Welcome to..."     |---->|  next    |
+----------+     |  (audio playing, please wait)|     |  action  |
                 +------------------------------+     +----------+
                              |
                    Cursor waits here until
                    audio finishes playing

Examples: talk, play, digits_receive, recording_start

Fire-and-Forget Actions (Dispatch and Continue)

These actions send something out but don’t wait for a response:

+------------+     +--------------------+
| email_send |---->| Email dispatched!  |----> Continue immediately
+------------+     | (delivery is async)|
                   +--------------------+

Examples: message_send, email_send, webhook_send

Blocking Actions (Pause Until Triggered)

These actions pause the flow until something external happens:

+----------+     +------------------------------+
|  block   |---->|  Flow is paused...           |
+----------+     |  Waiting for API call to     |
                 |  resume execution            |
                 +------------------------------+
                              |
                 Call POST /activeflows/{id}/execute
                              |
                              v
                 +------------------------------+
                 |  Flow resumes, cursor moves  |
                 +------------------------------+

Examples: block

Nested Actions (Push a Stack)

Some actions start a sub-flow that runs inside the main flow:

Main Flow:                                Nested Stack (from queue_join):
+--------+  +------------+               +-----------------------------+
| answer |->| queue_join |-------------->| wait_flow actions...        |
+--------+  +------------+               | (talk, play, etc.)          |
                  ^                      +-------------+---------------+
                  |                                    |
                  |      When agent answers or         |
                  |      caller hangs up               |
                  +------------------------------------+
                          Return to main flow

Examples: queue_join, ai_talk, conference_join, fetch_flow

Branching and Decision Making

Flows can make decisions and take different paths based on conditions.

The Branch Action

The branch action reads a variable and jumps to different actions based on its value:

+----------------------------------------------------------------------+
|                         Branch Decision                              |
+----------------------------------------------------------------------+

                          Variable value?
                                |
                +---------------+---------------+
                |               |               |
                v               v               v
              "1"             "2"           (default)
                |               |               |
                v               v               v
        +------------+  +------------+  +------------+
        |  Sales     |  |  Support   |  |  Operator  |
        |  menu      |  |  menu      |  |  (fallback)|
        +------------+  +------------+  +------------+

How Variables Get Set

Variables are set by previous actions and then read by branch:

Step 1: Collect input
+-----------------+
| digits_receive  |  -->  User presses "2"
+-----------------+       voipbin.call.digits = "2"

Step 2: Branch based on input
+-----------------+
|     branch      |  -->  Read voipbin.call.digits
|                 |       Value is "2"
| variable:       |       Jump to Support menu
|  voipbin.call.  |
|  digits         |
+-----------------+

Condition Actions

For more complex logic, use condition actions:

condition_variable:
+-------------------------------------------------------------------+
|  IF ${customer.tier} equals "premium"                             |
|     → Continue to next action (VIP treatment)                     |
|  ELSE                                                             |
|     → Jump to false_target_id (standard treatment)                |
+-------------------------------------------------------------------+

Available conditions: - equal, not_equal - greater, less - greater_equal, less_equal

The Variable System

Variables store information during flow execution. They’re like sticky notes that actions can write and read.

Built-in Variables

VoIPBIN automatically creates these variables:

+-----------------------------------------------------------------+
|                    Built-in Variables                           |
+---------------------------------+-------------------------------+
| voipbin.activeflow.id           | Current activeflow ID         |
+---------------------------------+-------------------------------+
| voipbin.activeflow.reference_id | The call/conversation ID      |
+---------------------------------+-------------------------------+
| voipbin.call.digits             | DTMF digits received          |
+---------------------------------+-------------------------------+
| voipbin.call.caller_id          | Caller's phone number         |
+---------------------------------+-------------------------------+
| voipbin.message.text            | Received message content      |
+---------------------------------+-------------------------------+
| voipbin.recording.id            | Current recording ID          |
+---------------------------------+-------------------------------+

Custom Variables

You can set your own variables with the variable_set action:

{
  "type": "variable_set",
  "option": {
    "key": "customer.language",
    "value": "en-US"
  }
}

Using Variables in Actions

Variables are substituted using ${variable.name} syntax:

{
  "type": "talk",
  "option": {
    "text": "Hello ${customer.name}, welcome back!",
    "language": "${customer.language}"
  }
}

Before this action executes, VoIPBIN replaces the placeholders:

Before: "Hello ${customer.name}, welcome back!"
After:  "Hello John Smith, welcome back!"

Unified flow

VoIPBIN’s Unified Flow feature is a game-changer, allowing users to create a single flow that can be attached to multiple communication channels, including voice and video calls, SMS, and RESTful API triggers.

With Unified Flow, users can design a custom flow that defines the actions to be taken when a specific channel request is received. VoIPBIN then automatically executes this flow, ensuring a consistent experience for customers across various channels.

Non-linear action execution

VoIPBIN’s Flow provides the flexibility of Non-Linear action execution.

Users can customize their actions in both linear and non-linear ways, allowing them to define complex logic and decision trees to handle various call scenarios.

Linear Execution:
+---+   +---+   +---+   +---+
| 1 |-->| 2 |-->| 3 |-->| 4 |
+---+   +---+   +---+   +---+

Non-Linear Execution (with goto and branch):
+---+   +---+   +---+   +---+
| 1 |-->| 2 |-->| 3 |-->| 4 |
+---+   +-+-+   +---+   +-+-+
          |               |
          |   +-----------+
          |   | (goto back to 2)
          v   v
        +-------+
        | Loop! |
        +-------+
_images/flow_overview_non_linear.png

Flow fork

Certain flow actions, such as fetch, fetch_flow, queue_join, and more, enable flow forking.

When the flow is forked, the execution cursor moves to the forked flow and starts executing the actions within it. Once the forked flow reaches its end, the execution cursor moves back to the following action of the forking action, continuing the flow execution.

Main Flow                         Forked Flow (from queue_join)
+---------+                      +---------------------------------+
| answer  |                      |                                 |
+----+----+                      |  +------+   +------+   +------+ |
     |                           |  | talk |-->| play |-->| talk | |
     v                           |  +------+   +------+   +------+ |
+------------+                   |         Wait Flow               |
| queue_join |==================>+---------------------------------+
+----+-------+                            |
     |                                    | (returns when done)
     |<===================================+
     |
     v
+----------+
| continue |
+----------+
_images/flow_overview_fork.png

Actions

Within VoIPBIN, actions dictate the course of the platform’s response in a given flow, encompassing tasks such as initiating calls, playing sounds or prompts, activating text-to-speech, sending SMS or DTMFs, and dispatching SNS messages. These diverse actions serve as indispensable building blocks for crafting customized voice applications, ensuring the creation of uniquely tailored call experiences for users.

VoIPBIN’s Flow provides developers with a versatile and robust toolkit, empowering them to forge dynamic voice applications, efficiently manage incoming calls, and curate personalized call encounters. Through its non-linear execution, cohesive flow capabilities, and an array of actions including SMS, DTMFs, SNS messages, and more, VoIPBIN’s Flow unveils limitless possibilities for the development of sophisticated and interactive voice applications, precisely tailored to meet specific business needs.

Action Categories

Category

Actions

Behavior

Media

talk, play, recording_start, recording_stop

Wait for completion

Input

digits_receive, transcribe_start

Wait for input

Control

goto, branch, condition_*, stop, empty

Immediate

Communication

message_send, email_send, webhook_send

Fire and forget

Nested

queue_join, ai_talk, conference_join, fetch

Push stack, return

Call Control

answer, hangup, hold, mute, connect, transfer

Immediate or wait

Flow execution

In VoIPBIN, the execution of flows is versatile and can be initiated through various methods:

Incoming/Outgoing Calls

VoIPBIN facilitates flow execution with both incoming and outgoing calls. Users have the option to register a flow to a specific number. Upon an incoming call to the registered number, VoIPBIN will seamlessly execute the associated flow. Users can also initiate a call with a predefined flow. Once the outgoing call is answered, the attached flow will be triggered.

Incoming Call Flow:
+--------------+      +-----------------+      +---------------+
|  Caller dials|----->|  VoIPBIN looks  |----->|  Flow starts  |
|  your number |      |  up the number  |      |  executing    |
+--------------+      +-----------------+      +---------------+

Outgoing Call Flow:
+--------------+      +-----------------+      +---------------+
|  POST /calls |----->|  Call connects  |----->|  Flow starts  |
|  with actions|      |  (answered)     |      |  executing    |
+--------------+      +-----------------+      +---------------+

Received Messages

VoIPBIN allows users to register flows to received messages. When a message is received, the registered flow will be executed. For example, you can register the flow like the below.

...
{
  "type": "branch",
  "option": {
    "variable": "voipbin.message.text",
    "target_ids": {
      "call me": "7a1e8c4c-aaea-11ed-9f0f-bffcc31ca3c3",
      "text me": "79fd8c9a-aaea-11ed-a238-0b094a49c637",
      "text developer": "73107b70-d56b-4b47-b331-dc4f2ac43a5b"
    }
  }
}
...

In the provided example, the system examines the content of the received message using voipbin.message.text and proceeds to compare the message text. Should the message text match the specified criterion, such as “call me,” the flow execution cursor will be directed to the designated action ID (7a1e8c4c-aaea-11ed-9f0f-bffcc31ca3c3) for subsequent execution. See the Variable Reference for all available variables.

Outbound Campaigns

The VoIPBIN platform integrates flows into outbound campaigns, providing a structured and automated approach to execution.

API

Users have the flexibility to trigger flows through API calls. This API integration empowers developers to seamlessly incorporate and activate flows within their applications. These diverse methods offer users and developers flexibility in integrating and executing flows based on their specific needs and scenarios. See the Activeflow API Reference for API details. And due to the absence of any media-based incoming or outgoing elements in the API, certain actions within the flow—such as answer, talk, transcribe, and others—will be ignored. Instead, the execution cursor will proceed to the next action in the sequence.

Flow Lifecycle

Understanding when flows start, run, and end helps you design reliable applications.

Flow States

+------------+         +------------+         +------------+
|  Created   |-------->|  Running   |-------->|   Ended    |
+------------+         +------------+         +------------+
      |                      |                      |
      |                      |                      |
Activeflow          Cursor executing         Final state
instance created    actions                  (no more changes)

What Ends a Flow

A flow ends when any of these happen:

+-----------------------------------------------------------------+
|                    Flow Termination Triggers                    |
+-----------------------------------------------------------------+

1. End of actions reached
   +---+   +---+   +---+   +---------+
   | 1 |-->| 2 |-->| 3 |-->|  END    |  ← Cursor reaches end
   +---+   +---+   +---+   +---------+

2. Stop action executed
   +---+   +------+
   | 1 |-->| stop |  ← Explicit stop command
   +---+   +------+

3. Call hangs up (for call-based flows)
   +---+   +---+   +---+
   | 1 |-->| 2 |-->| X |  ← Caller or callee hung up
   +---+   +---+   +---+

4. API stop request
   POST /activeflows/{id}/stop  ← External stop command

After Flow Ends

When a flow ends, if on_complete_flow_id is set, the next flow starts automatically (see below).

Flow Actions and Interrupt Actions

VoIPBIN’s Flow is built on an action-based engine. Each flow is defined as a JSON array of actions, where a “cursor” tracks the current execution point. Under normal circumstances, the cursor advances sequentially from one action to the next based on the flow’s logic. This modular design lets you compose a variety of call-handling scenarios—from answering calls and playing prompts to branching based on caller input.

Standard Flow Actions

Standard flow actions are the building blocks of your call handling logic. Examples include:

  • Answer: Picks up the incoming call.

  • Talk: Plays a TTS message or pre-recorded audio.

  • Digits Receive: Gathers DTMF input from the caller.

  • Branch: Directs the flow based on collected input.

Each action is executed in sequence, and upon completion, the flow cursor moves to the next action defined in the JSON array. For example:

{
  "id": "9bc851be-f05e-11ef-a1e0-77ec628521e0",
  "type": "flow",
  "name": "Sample Call Flow",
  "actions": [
    {
      "id": "9c8ebac0-f05e-11ef-b9ae-4b8aecc935fe",
      "type": "answer"
    },
    {
      "id": "9c30642a-f05e-11ef-8674-ebba44c5cb0f2",
      "type": "talk",
      "option": {
        "text": "Welcome to VoIPBIN",
        "language": "en-US"
      }
    },
    {
      "id": "9c659370-f05e-11ef-b141-63708262508b",
      "type": "digits_receive",
      "option": {
        "duration": 5000,
        "length": 1
      }
    },
    {
      "id": "9cb2962a-f05e-11ef-ae35-2374e1ae16df",
      "type": "branch",
      "option": {
        "variable": "voipbin.call.digits",
        "target_ids": {
          "1": "9c30642a-f05e-11ef-8674-ebba44c5cb0f2",
        }
      }
    }
  ]
}

In this example, the flow proceeds step-by-step—from answering the call to playing a welcome message, receiving DTMF input, and branching accordingly.

Interrupt Actions

Interrupt actions are specialized commands that can be triggered asynchronously—at any point during the flow—to handle unexpected events or to initiate high-priority tasks. Unlike standard actions, interrupt actions are designed to override or temporarily suspend the normal flow progression.

Normal Flow Execution              Interrupt Arrives!
+---+   +---+   +---+             +-----------------+
| 1 |-->| 2 |-->| 3 |<------------| Transfer Request|
+---+   +---+   +---+             +-----------------+
             ^                            |
             |                            v
             |                    +-----------------+
             |                    | Interrupt takes |
             +--------------------| over, then      |
               (resume later)     | returns         |
                                  +-----------------+

Common interrupt actions include:

  • Attended Transfer: Initiates a transfer even if the call is mid-flow. This allows an operator to consult with a transferee before completing the transfer.

  • Transcribe: Starts real-time transcription of the call. This can be triggered on demand without waiting for the current flow action to complete.

  • Recording: Begins or stops call recording independently of the flow’s sequential actions.

  • Text-to-Speech (TTS): Plays a TTS message at any moment, regardless of the flow’s current state.

How Interrupt Actions Work

Interrupt actions are implemented through dedicated API endpoints. When an interrupt is invoked, the platform either temporarily pauses the current flow or dynamically inserts the interrupt action into the execution sequence. Once the interrupt is handled, the flow resumes from the appropriate point.

For example, while the call is waiting for DTMF input in the standard flow, an attended transfer interrupt may be triggered via a separate API call. This immediate action takes precedence over the flow’s waiting state, ensuring that time-sensitive operations are executed without delay.

Integration and Best Practices

  • Flexibility: Use standard flow actions to define your routine call-handling steps, and rely on interrupt actions for events that require immediate attention.

  • API Integration: Interrupt actions can be initiated via dedicated API calls, enabling your application to react in real time to dynamic call events.

  • Flow Resumption: After an interrupt action completes, VoIPBIN resumes the flow from the designated point, ensuring a seamless call experience.

By combining sequential flow actions with the ability to trigger interrupt actions at any time, VoIPBIN provides a robust, programmable environment that can handle both predictable call scenarios and unexpected events with equal ease.

The on complete flow id

The on_complete_flow_id allows a flow to automatically trigger another flow in a new session once the current flow completes. This feature addresses a key limitation of call-based flows: when a call ends, the flow execution ends immediately, preventing any post-call actions (After Call Work) from running.

With on_complete_flow_id, developers can define a follow-up flow that executes after the call or flow ends, enabling tasks such as call-summary generation, sending emails, processing recordings, or running analytics.

How it works

+-----------------------------------------------------------------------+
|                    On Complete Flow Chain                             |
+-----------------------------------------------------------------------+

Flow A (Main Call Flow)                  Flow B (After Call Work)
+-------------------------+             +-------------------------+
| answer                  |             | fetch recording         |
| talk "Hello"            |             | ai_summarize            |
| connect to agent        |             | email_send summary      |
| (call happens...)       |             | webhook_send analytics  |
| hangup                  |             |                         |
|                         |             |                         |
| on_complete_flow_id: B  |------------>| (inherits variables)    |
+-------------------------+             +-------------------------+
          |                                        |
          | Call ends                              | Flow B starts
          | Flow A stops                           | automatically
          v                                        v
Caller             VoIPBIN Engine              Flow A                Flow B
|                      |                        |                     |
| --- Incoming Call -->|                        |                     |
|                      |-- Start Flow A ------->|                     |
|                      |                        | Execute actions     |
|                      |                        | answer/talk/...     |
|                      |                        |                     |
| <-- Call Progress -->|                        |                     |
|                      |                        |                     |
X --- Hangup --------->|                        |                     |
                       |-- Stop Flow A -------->|                     |
                       |                        X (Flow A stops)      |
                       |                                              |
                       |                                              |
            Check on_complete_flow_id                                 |
                       |                                              |
                       |                                              |
                       |-- Start NEW session ------------------------>|
                       |                                           (inherit variables)
                       |                                              |
                       |-- Start Flow B ----------------------------->|
                                                                      | Execute ACW actions
                                                                      | summarize/email/...
                                                                      |
                                                                      X (Flow B ends)
                                                                        If Flow B has on_complete_flow_id
                                                                        and depth < 5 then start another chain

When a flow ends—either by reaching the end of its action list, encountering a stop action, or due to call termination—VoIPBIN checks whether on_complete_flow_id is defined.

If so, VoIPBIN starts the referenced flow as a new independent session.

Most runtime variables from the original flow (e.g., ${voipbin.recording.id}, ${voipbin.call.id}) are inherited automatically, allowing seamless post-call workflows without requiring manual variable passing.

Variable Inheritance

Flow A ends with these variables:
+-----------------------------------------+
| voipbin.call.id = "abc-123"             |
| voipbin.recording.id = "rec-456"        |
| customer.name = "John"                  |
| voipbin.activeflow.complete_count = 0   |
+-----------------------------------------+
                     |
                     | copied to
                     v
Flow B starts with these variables:
+-----------------------------------------+
| voipbin.call.id = "abc-123"             |  ← inherited
| voipbin.recording.id = "rec-456"        |  ← inherited
| customer.name = "John"                  |  ← inherited
| voipbin.activeflow.complete_count = 1   |  ← incremented
+-----------------------------------------+

Execution limits

To prevent infinite recursion, VoIPBIN enforces:

Flow A --> Flow B --> Flow C --> Flow D --> Flow E --> STOP
  |          |          |          |          |
count=0    count=1    count=2    count=3    count=4
                                              |
                                              | count=5 would be blocked
                                              v
                                        Maximum depth reached
  • A maximum of 5 chained on-complete executions. Beyond this limit, no further follow-up flows are triggered.

  • Circular references should be avoided, even though safeguards exist.

Behavior on termination

  • If the flow fails, on_complete_flow_id is not triggered.

  • If the flow is forcefully terminated (e.g., due to call hangup), the on-complete flow still runs.

Example

{
  "id": "flow_initial",
  "on_complete_flow_id": "flow_after_call_work"
}

This configuration ensures that when flow_initial completes—regardless of how the call ended—the flow_after_call_work flow starts immediately in a new session, while preserving key session variables from the original flow.

Error Handling in Flows

When something goes wrong during flow execution, VoIPBIN handles it gracefully.

Error Scenarios

Scenario

What happens

Invalid action

Action is skipped, flow continues to next action

Media action fails

Error logged, flow continues or stops based on severity

External service down

Fire-and-forget actions continue, blocking ones may fail

Infinite loop detected

Flow stops after max iterations (safety limit)

Call hangs up

Flow ends immediately, on_complete_flow runs if set

Safety Limits

VoIPBIN prevents runaway flows with built-in limits:

Maximum iterations per execution cycle: 1000
Maximum total executions per activeflow: 100
Maximum on_complete_flow chain depth: 5

If these limits are exceeded, the flow stops automatically to protect system resources.

Best Practices for Error Handling

  1. Set default branches: Always include a default_target_id in branch actions

  2. Use timeouts: Configure appropriate durations for input actions

  3. Log with webhooks: Send important events to your webhook for monitoring

  4. Plan for hangup: Remember that call-based flows end when the call ends

Flow

Flow

{
    "id": "<string>",
    "type": "flow",
    "name": "test conference_join",
    "detail": "test flow for conference_join",
    "actions": [
        ...
    ],
    "tm_create": "2022-02-03 05:37:48.545532",
    "tm_update": "2022-02-03 06:10:23.604222",
    "tm_delete": "9999-01-01 00:00:00.000000"
},
  • id: Flow’s ID.

  • type: Flow’s types. See detail here.

  • name: Flow’s name.

  • detail: Flow’s detail.

  • actions: List of actions. See detail here.

Example .. code:

{
    "id": "ff8e4528-a743-4913-948c-81abaf563f80",
    "type": "flow",
    "name": "test flow for message sending",
    "detail": "test scenario for sending a test message.",
    "actions": [
        {
            "id": "605f5650-ba92-4dcd-bdac-91fcf6260939",
            "next_id": "00000000-0000-0000-0000-000000000000",
            "type": "message_send",
            "option": {
                "text": "hello, this is test message.",
                "source": {
                    "type": "tel",
                    "target": "+15559876543"
                },
                "destinations": [
                    {
                        "type": "tel",
                        "target": "+31616818985"
                    }
                ]
            }
        }
    ],
    "tm_create": "2022-03-21 02:11:15.033396",
    "tm_update": "9999-01-01 00:00:00.000000",
    "tm_delete": "9999-01-01 00:00:00.000000"
}

Type

type

Description

flow

Normal flow.

Action

Action

{
    "id": "<string>",
    "next_id": "<string>",
    "type": "<string>",
    "option": {
        ...
    },
    "tm_execute": "<string>"
}
  • id: Action’s id.

  • next_id: Action’s next id. If it sets empty, just move on to the next action in the action array.

  • type: Action’s type. See detail here.

  • option: Action’s option.

Type

type

Description

agent_call

Deprecated. Use the connect instead. Creates a call to the agent and connect.

amd

Answering machine detection.

answer

Answer the call.

beep

Play the beep sound.

branch

Branch gets the variable then execute the correspond action. For example. gets the dtmf input saved variable and jump to the action.

call

Starts a new independent outgoing call with a given flow.

chatbot_talk

Starts a talk with chatbot.

condition_call_digits

Deprecated. Use the condition_variable instead. Condition check(call’s digits).

condition_call_status

Deprecated. Use the condition_variable instead. Condition check(call’s status).

condition_datetime

Condition check(time)

condition_variable

Condition check(variable).

confbridge_join

Join to the confbridge.

conference_join

Join to the conference.

connect

Creates a new call to the destinations and connects to them.

conversation_send

Send a message to the conversation.

digits_receive

Receive the digits(dtmfs).

digits_send

Send the digits(dtmfs).

echo

Echo to stream.

external_media_start

Start the external media.

external_media_stop

Stop the external media.

fetch

Fetch the actions from endpoint.

fetch_flow

Fetch the actions from the exist flow.

goto

Goto.

hangup

Hangup the call.

hangup_relay

Hangs up the call with the same reason of the given reference id.

message_send

Send a message.

play

Play the file of the given urls.

queue_join

Join to the queue.

recording_start

Start the record of the given call.

recording_stop

Stop the record of the given call.

sleep

Sleep.

stop

Stop the flow.

stream_echo

Echo the steam.

talk

Generate audio from the given text(ssml or plain text) and play it.

transcribe_start

Start transcribe the call

transcribe_stop

Stop transcribe the call

transcribe_recording

Transcribe the recording and send it to webhook.

variable_set

Sets the variable.

webhook_send

Send a webhook.

Agent Call

Calling the agent. The agent may have various types of addresses or phone numbers, such as a desk phone, mobile phone, or softphone application.

Parameters

{
    "type": "agent_call",
    "option": {
        "agent_id": "<string>"
    }
}
  • agent_id: target agent id.

Example

{
    "type": "agent_call",
    "option": {
        "agent_id": "eb1ac5c0-ff63-47e2-bcdb-5da9c336eb4b"
    }
}

AMD

Answering machine detection.

Parameters

{
    "type": "amd",
    "option": {
        "machine_handle": "<string>",
        "async": <boolean>
    }
}
  • machine_handle: hangup,delay,continue if the machine answered a call. See detail here.

  • async: if it’s false, the call flow will be stop until amd done.

Machine handle

Type

Description

hangup

Hangup the call.

continue

Continue the call.

Example

{
    "type": "amd",
    "option": {
        "machine_handle": "hangup",
        "sync": true
    }
}

Answer

Answer the call

Parameters

{
    "type": "answer"
}

Example

{
    "type": "answer"
}

Beep

Make a beep sound.

Parameters

{
    "type": "beep"
}

Example

{
    "type": "beep"
}

Branch

Branch the flow. It gets the variable from the activeflow and move the activeflow cursor to the selected target id.

Parameters

{
    "type": "branch",
    "option": {
        "variable": "<string>",
        "default_target_id": "<string>",
        "target_ids": {
            "<string>": <string>,
        }
    }
}
  • variable: Target variable. If this value is empty, default target variable will be selected. Available variables are listed here. default: voipbin.call.digits

  • default_target_id: action id for default selection. This will be generated automatically by the given default_index.

  • target_ids: set of input digit and target id fair. This will be generated automatically by the given target_indexes.

Example

{
    "type": "branch",
    "option": {
        "default_target_id": "ed9705ca-c524-11ec-a3fb-8feb7731ad45",
        "target_ids": {
            "1": "c3eb8e62-c524-11ec-94c5-abafec8af561",
            "2": "dc87123e-c524-11ec-89c6-5fb18da14034",
            "3": "e70fb030-c524-11ec-b657-ebec72f097ef"
        }
    }
}

Call

Make a new outbound call in a new context.

_images/flow_action_call.png

Parameters

{
    "type": "call",
    "option": {
        "source": {
            ...
        },
        "destinations": [
            {
                ...
            },
            ...
        ],
        "flow_id": "<string>"
        "actions": [
            {
                ...
            }
        ],
        "chained": <boolean>,
        "early_execution": <boolean>
    }
}
  • source: Source address. See detail here.

  • destinations: Array of destination addresses. See detail here.

  • flow_id: Call’s flow id. If this not set, will use the actions array.

  • actions: Array of actions. If the flow_id not set, the call flow will be created with this actions.

  • chained: If it sets to true, created calls will be hungup when the master call is hangup. Default false.

  • early_execution: It it sets to true, the voipbin will execute the flow when then call is ringing.

Example

{
    "id": "e34ab97a-c53a-4eb4-aebf-36767a528f00",
    "next_id": "00000000-0000-0000-0000-000000000000",
    "type": "call",
    "option": {
        "source": {
            "type": "tel",
            "target": "+821100000001"
        },
        "destinations": [
            {
                "type": "tel",
                "target": "+821100000002"
            }
        ],
        "actions": [
            {
                "type": "talk",
                "option": {
                    "text": "hello, this is test message.",
                    "language": "en-US"
                }
            }
        ],
        "chained": false
    }
}

Chatbot Talk

Start the chatbot talk.

Parameters

{
    "type": "chatbot_talk",
    "option": {
        "chatbot_id": "<string>",
        "gender": "<string>",
        "language": "<string>",
        "duration": <number>
    }
}
  • chatbot_id: Chatbot id.

  • gender: Voice gender. male/female/neutral

  • language: Specifies the language. BCP47 format.

  • duration: Duration. Seconds.

Confbridge Join

Join to the confbridge.

Parameters

{
    "type": "confbridge_join",
    "option": {
        "confbridge_id": "<string>"
    }
}
  • confbridge_id: Target confbridge id.

Condition Call Digits

Deprecated. Use the condition_variable instead. Check the condition of received digits. If the conditions are met, the system proceeds to the next action. If the conditions are not met, the voipbin directs the call to a false_target_id for further processing.

Parameters

{
    "type": "condition_call_digits",
    "option": {
        "length": <number>,
        "key": "<string>",
        "false_target_id": "<string>"
    }
}
  • length: match digits length.

  • key: match digits contain.

  • false_target_id: action id for false condition.

Example

{
    "type": "condition_call_digits",
    "option": {
        "length": 10,
        "false_target_id": "e3e50e6c-9c8b-11ec-8031-0384a8fcd1e2"
    }
}

Condition Call Status

Deprecated. Use the condition_variable instead. Check the condition of call’s status. It checks the call’s status and if it matched with condition then move to the next action. If not, move to the false_target_id.

Parameters

{
    "type": "condition_call_status",
    "option": {
        "status": <number>,
        "false_target_id": "<string>"
    }
}
  • status: match call’s status. See detail here.

  • false_target_id: action id for false condition.

Example

{
    "type": "condition_call_status",
    "option": {
        "status": "progressing,
        "false_target_id": "e3e50e6c-9c8b-11ec-8031-0384a8fcd1e2"
    }
}

Condition Datetime

Check the condition of the time. It checks the current time(UTC) and if it matched with condition then move to the next action. If not, move to the false_target_id.

Parameters

{
    "type": "condition_datetime",
    "option": {
        "condition": <number>,

        "minute": <number>,
        "hour": <number>,
        "day": <number>,
        "month": <number>,
        "weekdays": [
            <number>,
            ...
        ],


        "false_target_id": "<string>"
    }
}
  • condition: Match condition. One of “==”, “!=”, “>”, “>=”, “<”, “<=”.

  • minute: Minutes. -1 for all minutes.

  • hour: Hour. -1 for all hours.

  • day: Day. -1 for all days.

  • month: Month. 0 for all months.

  • weekdays: List of weekdays. Sunday: 0, Monday: 1, Tuesday: 2, Wednesday: 3, Thursday: 4, Friday: 5, Saturday: 6

  • false_target_id: action id for false condition.

Example

{
    "type": "condition_datetime",
    "option": {
        "condition": ">=,
        "minute": 0
        "hour": 8,
        "day": -1,
        "month": 0,
        "weekdays": [],
        "false_target_id": "d08582ee-1b3d-11ed-a43e-9379f27c3f7f"
    }
}

Condition Variable

Check the condition of the given variable. It checks the call’s status and if it matched with condition then move to the next action. If not, move to the false_target_id.

Parameters

{
    "type": "condition_variable",
    "option": {
        "condition": "<string>",
        "variable": "<string>",
        "value_type": "<string>",
        "value_string": "<string>",
        "value_number": <number>,
        "value_length": <number>,
        "false_target_id": "<string>"
    }
}
  • condition: Match condition. One of “==”, “!=”, “>”, “>=”, “<”, “<=”.

  • variable: Target variable. See detail here.

  • value_type: Type of value. string/number/length.

  • value_string: Value. Valid only if the value_type is string.

  • value_number: Value. Valid only if the value_type is number.

  • value_length: Value. Valid only if the value_type is length.

  • false_target_id: action id for false condition.

Example

{
    "type": "condition_variable",
    "option": {
        "condition": "==",
        "variable": "voipbin.call.source.target",
        "value_type": "string",
        "value_string": "+821100000001",
        "false_target_id": "fb2f4e2a-b030-11ed-bddb-976af892f5a3"
    }
}

Conference Join

Join to the conference

Parameters

{
    "type": "conference_join",
    "option": {
        "conference_id": "<string>"
    }
}
  • conference_id: Conference’s id to join.

Example

{
    "type": "conference_join",
    "option": {
        "conference_id": "367e0e7a-3a8c-11eb-bb08-f3c3f059cfbe"
    }
}

Connect

Originate to the other destination(s) and connect to them each other.

Parameters

{
    "type": "connect",
    "option": {
        "source": {...},
        "destinations": [
            ...
        ],
        "early_media": <boolean>,
        "relay_reason": <boolean>
    }
}
  • source: Source address. See detail here.

  • destinations: Array of destination addresses. See detail here.

  • early_media: Support early media.

  • relay_reason: relay the hangup reason to the master call.

Example

{
    "type": "connect",
    "option": {
        "source": {
            "type": "tel",
            "target": "+11111111111111"
        },
        "destinations": [
            {
                "type": "tel",
                "target": "+222222222222222"
            }
        ]
    }
}

Conversation send

Send the message to the conversation.

Parameters

{
    "type": "conversation_send",
    "option": {
        "conversation_id": "<string>",
        "text": "<string>",
        "sync": <boolean>
    }
}
  • conversation_id: Target conversation id.

  • text: Send text message.

  • sync: If this set to true, waits until this action done.

Example

{
    "type": "conversation_send",
    "option": {
        "conversation_id": "b5ef5e64-f7ca-11ec-bbe9-9f74186a2a72",
        "text": "hello world, this is test message.",
        "sync": false
    }
}

Digits Receive

Receives the digits for given duration or numbers.

Parameters

{
    "type": "digits_receive",
    "option": {
        "duration": <number>,
        "length": <number>,
        "key": "<string>"
    }
}
  • duration: The duration allows you to set the limit (in ms) that VoIPBIN will wait for the endpoint to press another digit or say another word before it continue to the next action.

  • length: You can set the number of DTMFs you expect. An optional limit to the number of DTMF events that should be gathered before continuing to the next action. By default, this is set to 1, so any key will trigger the next step. If EndKey is set and MaxNumKeys is unset, no limit for the number of keys that will be gathered will be imposed. It is possible for less keys to be gathered if the EndKey is pressed or the timeout being reached.

  • key: If set, determines which DTMF triggers the next step. The finish_on_key will be included in the resulting variable. If not set, no key will trigger the next action.

Example

{
    "type": "digits_receive",
    "option": {
        "duration": 10000,
        "length": 3,
        "key": "#"
    }
}

Digits Send

Sends the digits with given duration and interval.

Parameters

{
    "type": "digits_send",
    "option": {
        "digits": "<string>",
        "duration": <number>,
        "interval": <number>
    }
}
  • digits: The digit string to send. Allowed set of characters: 0-9,A-D, #, ‘*’; with a maximum of 100 keys.

  • duration: The duration of DTMF tone per key in milliseconds. Allowed values: Between 100 and 1000.

  • interval: Interval between sending keys in milliseconds. Allowed values: Between 0 and 5000.

Example

{
    "type": "digits_send",
    "option": {
        "digits": "1234567890",
        "duration": 500,
        "interval": 500
    }
},

Echo

Echoing the call.

Parameters

{
    "type": "echo",
    "option": {
        "duration": <number>,
    }
}
  • duration: Echo duration. ms.

Example

{
    "type": "echo",
    "option": {
        "duration": 30000
    }
}

External Media Start

Start the external media.

Parameters

{
    "type": "external_media_start",
    "option": {
        "external_host": "<string>",
        "encapsulation": "<string>",
        "transport": "<string>",
        "connection_type": "<string>",
        "format": "<string>",
        "direction": "<string>",
        "data": "<string>"
    }
}
  • external_host: external media target host address.

  • encapsulation: encapsulation. default: rtp.

  • transport: transport. default: udp.

  • connection_type: connection type. default: client

  • format: format default: ulaw

  • direction: Direction. default: both.

  • data: Data. Reserved.

External Media Stop

Stop the external media.

Parameters

{
    "type": "external_media_stop",
}

Fetch

Fetch the next flow from the remote.

Parameters

{
    "type": "fetch",
    "option": {
        "event_url": "<string>",
        "event_method": "<string>"
    }
}
  • event_url: The url for flow fetching.

  • event_method: The method for flow fetching.

Example

{
    "type": "fetch",
    "option": {
        "event_method": "POST",
        "event_url": "https://webhook.site/e47c9b40-662c-4d20-a288-6777360fa211"
    }
}

Fetch Flow

Fetch the next flow from the existing flow.

Parameters

{
    "type": "fetch_flow",
    "option": {
        "flow_id": "<string>"
    }
}
  • flow_id: The id of flow.

Example

{
    "type": "fetch_flow",
    "option": {
        "flow_id": "212a32a8-9529-11ec-8bf0-8b89df407b6e"
    }
}

Goto

Move the action execution.

Parameters

{
    "type": "goto",
    "option": {
        "target_id": "<string>",
        "loop_count": <integer>
    }
}
  • target_id: action id for move target.

  • loop_count: The number of loop.

Example

{
    "type": "goto",
    "option": {
        "target_id": "ca4ddd74-9c8d-11ec-818d-d7cf1487e8df",
        "loop_count": 2
    }
}

Hangup

Hangup the call.

Parameters

{
    "type": "hangup"
}

Example

{
    "type": "hangup"
}

Hangup Relay

Hangup the call and relay the hangup cause to the reference id.

Parameters

{
    "type": "hangup_relay",
    "option": {
        "reference_id": "<string>"
    }
}

Example

{
    "type": "hangup_relay",
    "option": {
        "reference_id": "b8573f30-b031-11ed-ac05-3bc9a62e64c3"
    }
}

Message send

Send a message.

Parameters

{
    "type": "message_send",
    "option": {
        "source": {
            ...
        },
        "destinations": [
            {
                ...
            },
            ...
        ],
        "text": "<string>"
    }
}
  • source: Source address info. See detail here.

  • destinations: Array of destination addresses. See detail here.

  • text: Message’s text.

Play

Plays the linked file.

Parameters

{
    "type": "play",
    "option": {
        "stream_urls": [
            "<string>",
            ...
        ]
    }
}
  • stream_urls: Stream url array for media.

Example

{
    "type": "play",
    "option": {
        "stream_urls": [
            "https://github.com/pchero/asterisk-medias/raw/master/samples_codec/pcm_samples/example-mono_16bit_8khz_pcm.wav"
        ]
    }
}

Queue Join

Join to the queue.

Parameters

{
    "type": "queue_join",
    "option": {
        "queue_id": "<string>"
    }
}
  • queue_id: Target queue id.

Example

{
    "type": "queue_join",
    "option": {
        "queue_id": "99bf739a-932f-433c-b1bf-103d33d7e9bb"
    }
}

Recording Start

Starts the call recording.

Parameters

{
    "type": "recording_start",
    "option": {
        "format": "<string>",
        "end_of_silence": <integer>,
        "end_of_key": "<string>",
        "duration": <integer>,
        "beep_start": <boolean>
    }
}
  • format: Format to encode audio in. wav, mp3, ogg.

  • end_of_silence: Maximum duration of silence, in seconds. 0 for no limit.

  • end_of_key: DTMF input to terminate recording. none, any, *, #.

  • duration: Maximum duration of the recording, in seconds. 0 for no limit.

  • beep_start: Play beep when recording begins

Example

{
    "type": "recording_start",
    "option": {
        "format": "wav"
    }
}

Recording Stop

Stops the call recording.

Parameters

{
    "type": "recording_stop"
}

Example

{
    "type": "recording_stop"
}

Sleep

Sleep the call.

Parameters

{
    "type": "sleep",
    "option": {
        "duration": <number>
    }
}
  • duration: Sleep duration(ms).

Stream Echo

Echoing the RTP stream including the digits receive.

Parameters

{
    "type": "stream_echo",
    "option": {
        "duration": <number>
    }
}
  • duration: Echo duration. ms.

Example

{
    "type": "stream_echo",
    "option": {
        "duration": 10000
    }
}

Talk

Text to speech. SSML(https://www.w3.org/TR/speech-synthesis/) supported.

Parameters

{
    "type": "talk",
    "option": {
        "text": "<string>",
        "language": "<string>",
        "provider": "<string>",
        "voice_id": "<string>",
        "digits_handle": "<string>"
    }
}
  • text: Text to speech. SSML(https://cloud.google.com/text-to-speech/docs/ssml) supported.

  • language: Specifies the language. The value may contain a lowercase, two-letter language code (for example, en), or the language code and uppercase country/region (for example, en-US).

  • provider: TTS provider. Optional. gcp (Google Cloud TTS) or aws (AWS Polly). If omitted, defaults to GCP. If the selected provider fails, the system automatically falls back to the alternative provider with the default voice for the language.

  • voice_id: Provider-specific voice identifier. Optional. For example, en-US-Wavenet-D (GCP) or Joanna (AWS). On fallback, the voice_id is reset to the alternative provider’s default voice.

  • digits_handle: See detail here.

Digits handle

Type

Description

next

If digits received in talk, move the action to the next.

Example

{
    "type": "talk",
    "option": {
        "text": "Hello. Welcome to voipbin. This is test message. Please enjoy the voipbin service. Thank you. Bye",
        "language": "en-US"
    }
}

Transcribe recording

Transcribe the call’s recordings.

Parameters

{
    "type": "transcribe_recording",
    "option": {
        "language": "<string>"
    }
}
  • language: Specifies the language. BCP47 format.

Example

{
    "type": "transcribe_recording",
    "option": {
        "language": "en-US"
    }
}

Transcribe start

Start the STT(Speech to text) transcribe in realtime.

Parameters

{
    "type": "transcribe_start",
    "option": {
        "language": "<string>",
    }
}
  • language: Specifies the language. BCP47 format. The value may contain a lowercase, two-letter language code (for example, en), or the language code and uppercase country/region (for example, en-US).

Example

{
    "type": "transcribe_start",
    "option": {
        "language": "en-US",
    }
}

Transcribe stop

Stop the transcribe talk in realtime.

Parameters

{
    "type": "transcribe_stop"
}

Example

{
    "type": "transcribe_stop"
}

Variable Set

Set a variable value for use in the flow.

Parameters

{
    "type": "variable_set",
    "option": {
        "key": "<string>",
        "value": "<string>"
    }
}
  • key: Variable name.

  • value: Variable value.

Example

{
    "type": "variable_set",
    "option": {
        "key": "Provider name",
        "value": "voipbin"
    }
}

Webhook send

Send a webhook.

Parameters

{
    "type": "webhook_send",
    "option": {
        "sync": boolean,
        "uri": "<string>",
        "method": "<string>",
        "data_type": "<string>",
        "data": "<string>"
    }
}
  • sync: If this set to true, waits until this action done.

  • uri: Destination uri.

  • method: HTTP method. Supported values: POST, GET, PUT, DELETE.

  • data_type: Content type of the data. For example: application/json.

  • data: Data string. Variable can be used.

Example

{
    "type": "webhook_send",
    "option": {
        "sync": true,
        "uri": "https://test.com",
        "method": "POST",
        "data_type": "application/json",
        "data": "{\"destination_number\": \"${voipbin.call.destination.target}\", \"source_number\": \"${voipbin.call.source.target}\"}"
    }
}

Tutorial basic

Get list of flows

Gets the list of registered flows.

$ curl -k --location --request GET 'https://api.voipbin.net/v1.0/flows?token=<YOUR_AUTH_TOKEN>'

{
    "result": [
        {
            "id": "decc2634-0b2a-11eb-b38d-87a8f1051188",
            "name": "default flow",
            "detail": "default flow for voipbin incoming calls",
            "actions": [
                {
                    "id": "b34aa8a4-0b30-11eb-8016-1f5bc75b1c04",
                    "type": "play",
                    "option": {
                        "stream_url": [
                            "https://github.com/pchero/asterisk-medias/raw/master/voipbin/welcome.wav"
                        ]
                    }
                },
                {
                    "id": "57a3dcd2-0b2b-11eb-94a6-a7129b64693c",
                    "type": "play",
                    "option": {
                        "stream_url": [
                            "https://github.com/pchero/asterisk-medias/raw/master/samples_codec/pcm_samples/example-mono_16bit_8khz_pcm.wav"
                        ]
                    }
                }
            ],
            "tm_create": "2020-10-11 01:00:00.000001",
            "tm_update": "",
            "tm_delete": ""
        },
        {
            "id": "af9dae94-ef07-11ea-a101-8f52e568f39b",
            "name": "test flow",
            "detail": "manual flow test",
            "actions": [
                {
                    "id": "00000000-0000-0000-0000-000000000000",
                    "type": "echo"
                }
            ],
            "tm_create": "2020-09-04 23:53:14.496918",
            "tm_update": "",
            "tm_delete": ""
        }
    ],
    "next_page_token": "2020-09-04 23:53:14.496918"
}

Get detail of specified flow

Gets the detail of registered flows.

$ curl -k --location --request GET 'https://api.voipbin.net/v1.0/flows/decc2634-0b2a-11eb-b38d-87a8f1051188?token=<YOUR_AUTH_TOKEN>'

{
    "id": "decc2634-0b2a-11eb-b38d-87a8f1051188",
    "name": "default flow",
    "detail": "default flow for voipbin incoming calls",
    "actions": [
        {
            "id": "b34aa8a4-0b30-11eb-8016-1f5bc75b1c04",
            "type": "play",
            "option": {
                "stream_url": [
                    "https://github.com/pchero/asterisk-medias/raw/master/voipbin/welcome.wav"
                ]
            }
        },
        {
            "id": "57a3dcd2-0b2b-11eb-94a6-a7129b64693c",
            "type": "play",
            "option": {
                "stream_url": [
                    "https://github.com/pchero/asterisk-medias/raw/master/samples_codec/pcm_samples/example-mono_16bit_8khz_pcm.wav"
                ]
            }
        }
    ],
    "tm_create": "2020-10-11 01:00:00.000001",
    "tm_update": "",
    "tm_delete": ""
}

Create a flow

Create a new flow for incoming call requests. When the call is incoming, this flow will answer the call first, then speak the welcome text.

$ curl -k --location --request POST 'https://api.voipbin.net/v1.0/flows?token=<YOUR_AUTH_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "test flow",
    "detail": "test voipbin flow example",
    "actions": [
        {
            "type": "answer"
        },
        {
            "type": "talk",
            "option": {
                "text": "hello. welcome to voipbin. This is test message. Please enjoy the voipbin'\''s service. thank you.",
                "language": "en-US"
            }
        }
    ]
}'

{
    "id": "24013a0e-d15b-4b5e-9a96-04221a8c6a15",
    "name": "test flow",
    "detail": "test voipbin flow example",
    "actions": [
        {
            "id": "9461bda1-54fd-4e27-ab04-4186c6f72830",
            "type": "answer"
        },
        {
            "id": "69af787e-f5fa-4a1b-9d12-f0b43b86dae6",
            "type": "talk",
            "option": {
                "text": "hello. welcome to voipbin. This is test message. Please enjoy the voipbin's service. thank you.",
                "language": "en-US"
            }
        }
    ],
    "tm_create": "2021-02-04 06:47:01.139361",
    "tm_update": "",
    "tm_delete": ""
}

Update the flow

Update an existing flow with the given information. This doesn’t affect existing calls. Flow changes will only affect new calls.

$ curl -k --location --request PUT 'https://api.voipbin.net/v1.0/flows/decc2634-0b2a-11eb-b38d-87a8f1051188?token=<YOUR_AUTH_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "test flow update",
    "detail": "test voipbin flow example update",
    "actions": [
        {
            "type": "answer"
        },
        {
            "type": "talk",
            "option": {
                "text": "hello. welcome to voipbin. This is test message. Please enjoy the voipbin'\''s service. thank you.",
                "language": "en-US"
            }
        },
        {
            "type": "play",
            "option": {
                "stream_url": [
                    "https://github.com/pchero/asterisk-medias/raw/master/voipbin/welcome.wav"
                ]
            }
        },
        {
            "type": "play",
            "option": {
                "stream_url": [
                    "https://github.com/pchero/asterisk-medias/raw/master/samples_codec/pcm_samples/example-mono_16bit_8khz_pcm.wav"
                ]
            }
        }
    ]
}'

{
    "id": "decc2634-0b2a-11eb-b38d-87a8f1051188",
    "name": "test flow update",
    "detail": "test voipbin flow example update",
    "actions": [
        {
            "id": "be682498-e57e-41e9-b210-a578f9c044c5",
            "type": "answer"
        },
        {
            "id": "6669bfdd-a7b0-45e6-9a8d-db6bb898159f",
            "type": "talk",
            "option": {
                "text": "hello. welcome to voipbin. This is test message. Please enjoy the voipbin's service. thank you.",
                "language": "en-US"
            }
        },
        {
            "id": "099b60c1-7b95-4d69-8cac-df11a992ee11",
            "type": "play",
            "option": {
                "stream_url": [
                    "https://github.com/pchero/asterisk-medias/raw/master/voipbin/welcome.wav"
                ]
            }
        },
        {
            "id": "89fa5091-a192-4758-8a29-316776ead8fe",
            "type": "play",
            "option": {
                "stream_url": [
                    "https://github.com/pchero/asterisk-medias/raw/master/samples_codec/pcm_samples/example-mono_16bit_8khz_pcm.wav"
                ]
            }
        }
    ],
    "tm_create": "2020-10-11 01:00:00.000001",
    "tm_update": "2021-02-05 13:08:56.113036",
    "tm_delete": ""
}

Delete the flow

Delete an existing flow by its flow ID. This doesn’t affect existing calls.

$ curl -k --location --request GET 'https://api.voipbin.net/v1.0/flows/af9dae94-ef07-11ea-a101-8f52e568f39b?token=<YOUR_AUTH_TOKEN>' \

Tutorial scenario

Simple voicemail

Making a outgoing call for forwarding. If call not answered, leave a voicemail.

               Start
                 |
                 |
             Connect(Making an outgoing call for forwarding)
                 |
                 |
             Condition check(check the call's status is Answered)
                 |
                 |
    ------------------------------
    |                            |
condition false               condition true
    |                            |
    |                          Hangup
  Talk(...)
    |
    |
  Beep
    |
    |
 Recording start
    |
    |
  Sleep(10 sec)
    |
    |
  Hangup
{
    "actions": [
        {
            "type": "connect",
            "option": {
                "source": {
                    "type": "tel",
                    "target": "+15559876543"
                },
                "destinations": [
                    {
                        "type": "tel",
                        "target": "+15551112222"
                    }
                ]
            }
        },
        {
            "id": "3746e628-8cc1-4ff4-82fe-194b16b9a10e",
            "next_id": "00000000-0000-0000-0000-000000000000",
            "type": "condition_call_status",
            "option": {
                "status": "progressing",
                "false_target_id": "cfe0e8ea-991c-11ec-b849-d7fc54168fd5"
            }
        },
        {
            "id": "58f859e9-92d8-4b46-8073-722b9c881ae0",
            "next_id": "00000000-0000-0000-0000-000000000000",
            "type": "hangup"
        },
        {
            "id": "cfe0e8ea-991c-11ec-b849-d7fc54168fd5",
            "next_id": "00000000-0000-0000-0000-000000000000",
            "type": "talk",
            "option": {
                "text": "Thank you for your calling. We are busy now. Please leave a message after tone.",
                "language": "en-US"
            }
        },
        {
            "id": "0a9b6f38-ddcd-448b-80a1-ae47ac0e08aa",
            "next_id": "00000000-0000-0000-0000-000000000000",
            "type": "beep"
        },
        {
            "id": "ad969315-6ac4-4339-b300-566eb6352fea",
            "next_id": "00000000-0000-0000-0000-000000000000",
            "type": "recording_start",
            "option": {
                "beep_start": true
            }
        },
        {
            "id": "8abf3f9d-414c-4a15-aa94-02a799409f48",
            "next_id": "00000000-0000-0000-0000-000000000000",
            "type": "sleep",
            "option": {
                "duration": 10000
            }
        },
        {
            "id": "e4fc5d9e-9fa8-4b3e-ae77-b55b04c1f2d3",
            "next_id": "00000000-0000-0000-0000-000000000000",
            "type": "hangup"
        }
    ]
}

Simple branch

It will get the digits from the call and will execute the branch.

              Start
                |
                |
------------>  Talk("Press 1 for show must go on. Press 2 for bohemian rhapsody. Press 3 for another one bites the dust")
|               |
|               |
|              Digit(DTMF) receive
|               |
|               |
|       -----------------------------------------------
|       |           |                |                |
|     default      "1"              "2"              "3"
|       |           |                |                |
|       |           |                |                |
|       |          Talk(...)        Talk(...)        Talk(...)
|       |           |                |                |
|       |           |                |                |
|       |          Hangup          Hangup           Hangup
|       |
|       |
|      Talk(...)
|       |
----goto(loop 3 times)
        |
        |
       Talk(...)
        |
        |
       Hangup
{
    "actions": [
        {
            "id": "b8781e56-c524-11ec-889f-d37b0dbb7eb8",
            "type": "talk",
            "option": {
                "text": "Hello. This is branch test. Press 1 for show must go on. Press 2 for bohemian rhapsody. Press 3 for another one bites the dust",
                "language": "en-US"
            }
        },
        {
            "type": "digits_receive",
            "option": {
                "duration": 5000,
                "length": 1
            }
        },
        {
            "type": "branch",
            "option": {
                "default_target_id": "ed9705ca-c524-11ec-a3fb-8feb7731ad45",
                "target_ids": {
                    "1": "c3eb8e62-c524-11ec-94c5-abafec8af561",
                    "2": "dc87123e-c524-11ec-89c6-5fb18da14034",
                    "3": "e70fb030-c524-11ec-b657-ebec72f097ef"
                }
            }
        },
        {
            "id": "c3eb8e62-c524-11ec-94c5-abafec8af561",
            "type": "talk",
            "option": {
                "text": "Empty spaces, what are we living for? Abandoned places, I guess we know the score, on and on. Does anybody know what we are looking for? Another hero, another mindless crime. Behind the curtain, in the pantomime",
                "language": "en-US"
            }
        },
        {
            "type": "hangup"
        },
        {
            "id": "dc87123e-c524-11ec-89c6-5fb18da14034",
            "type": "talk",
            "option": {
                "text": "Mama, Just killed a man. Put a gun against his head, pulled my trigger. Now he's dead. Mama, life had just begun, But now I've gone and thrown it all away.",
                "language": "en-US"
            }
        },
        {
            "type": "hangup"
        },
        {
            "id": "e70fb030-c524-11ec-b657-ebec72f097ef",
            "type": "talk",
            "option": {
                "text": "Steve walks warily down the street. With his brim pulled way down low. Ain't no sound but the sound of his feet. Machine guns ready to go. Are you ready hey are you ready for this?",
                "language": "en-US"
            }
        },
        {
            "type": "hangup"
        },
        {
            "id": "ed9705ca-c524-11ec-a3fb-8feb7731ad45",
            "type": "talk",
            "option": {
                "text": "You didn't choose the correct number. Default selected.",
                "language": "en-US"
            }
        },
        {
            "type": "goto",
            "option": {
                "target_id": "b8781e56-c524-11ec-889f-d37b0dbb7eb8",
                "loop_count": 2
            }
        },
        {
            "type": "talk",
            "option": {
                "text": "Loop over. Hangup the call. Thank you, good bye.",
                "language": "en-US"
            }
        },
        {
            "type": "hangup"
        }
    ]
}

Simple message send

Send the message to the multiple destinations.

Start
  |
  |
Message send
  |
  |
 End
{
    "actions": [
        {
            "type": "message_send",
            "option": {
                "source": {
                    "type": "tel",
                    "target": "+821100000001"
                },
                "destinations": [
                    {
                        "type": "tel",
                        "target": "+821100000002"
                    },
                    {
                        "type": "tel",
                        "target": "+821100000003"
                    },
                    {
                        "type": "tel",
                        "target": "+821100000004"
                    }
                ],
                "text": "hello, this is test message."
            }
        }
    ]
}

Simple message send and make a new outbound call

Send the message to the destination and start a new outbound call with talk action.

Start
  |
  |
Message send
  |
  |
Call ------------------- Start
  |                        |
  |                        |
 End                      Talk
                           |
                           |
                          End
{
    "actions": [
        {
            "type": "message_send",
            "option": {
                "source": {
                    "type": "tel",
                    "target": "+821100000001"
                },
                "destinations": [
                    {
                        "type": "tel",
                        "target": "+821100000002"
                    }
                ],
                "text": "hello, this is test message."
            },
            {
                "type": "call",
                "option": {
                    "source": {
                        "type": "tel",
                        "target": "+821100000001"
                    },
                    "destinations": [
                        {
                            "type": "tel",
                            "target": "+821100000003"
                        }
                    ],
                    "actions": [
                        {
                            "type": "talk",
                            "option": {
                                "text": "hello, this is test message.",
                                "language": "en-US"
                            }
                        }
                    ]
                }
            }
        }
    ]
}

Flow Execution Internals

This section provides deep technical details about how VoIPBIN’s flow engine executes actions internally, including the interaction between services and the state machine that drives flow execution.

Flow Manager Architecture

The flow-manager service is responsible for executing all flow logic:

Flow Manager Internal Architecture:

+------------------------------------------------------------------+
|                        bin-flow-manager                          |
+------------------------------------------------------------------+
|                                                                  |
|  +------------------+    +------------------+    +-------------+ |
|  | Listen Handler   |    | Flow Handler     |    | Action      | |
|  | (RabbitMQ RPC)   |--->| (Orchestrator)   |--->| Executors   | |
|  +------------------+    +------------------+    +-------------+ |
|           |                      |                     |         |
|           v                      v                     v         |
|  +------------------+    +------------------+    +-------------+ |
|  | Request Router   |    | Activeflow       |    | External    | |
|  | (message types)  |    | State Machine    |    | Services    | |
|  +------------------+    +------------------+    +-------------+ |
|                                  |                               |
+----------------------------------+-------------------------------+
                                   |
                                   v
+------------------------------------------------------------------+
|                    Database Layer (MySQL)                        |
|  +------------------+    +------------------+    +-------------+ |
|  | activeflows      |    | flows            |    | variables   | |
|  | (runtime state)  |    | (definitions)    |    | (runtime)   | |
+------------------------------------------------------------------+

Activeflow Lifecycle

When a flow executes, an “activeflow” instance is created to track its state:

Activeflow State Transitions:

+----------+     +-----------+     +-----------+     +----------+
| created  |---->| executing |---->| waiting   |---->| ended    |
+----------+     +-----------+     +-----------+     +----------+
     |                |                 |                 ^
     |                |                 |                 |
     |                v                 v                 |
     |           +-----------+     +-----------+          |
     |           | error     |     | blocked   |          |
     |           +-----------+     +-----------+          |
     |                |                 |                 |
     |                +-----------------+-----------------+
     |                                  |
     +----------------------------------+
               (any state can end)


Activeflow Database Record:
+------------------------------------------------------------------+
| id: uuid                    | Unique activeflow identifier       |
| flow_id: uuid               | Reference to flow definition       |
| customer_id: uuid           | Owner of this execution            |
| reference_type: string      | "call", "message", "api"           |
| reference_id: uuid          | Associated call/message ID         |
| current_action_id: uuid     | Cursor position in flow            |
| status: string              | Current execution state            |
| variables: json             | Runtime variable storage           |
| forward_action_id: uuid     | For nested flow returns            |
| stack_depth: int            | Nested execution depth             |
| execute_count: int          | Safety counter                     |
+------------------------------------------------------------------+

Execution Loop Detail

The core execution loop processes actions one at a time:

Flow Execution Loop:

+------------------------------------------------------------------+
|                     Execution Engine                             |
+------------------------------------------------------------------+

1. Get Next Action
+-----------------+
| Load activeflow |
| from database   |
+--------+--------+
         |
         v
+------------------+
| Get action by    |
| current_action_id|
+--------+---------+
         |
         v
2. Execute Action
+------------------+     +-----------------------------------+
| Action Executor  |---->| Action-specific logic:            |
| Factory          |     | - talk: Generate TTS, send media  |
+------------------+     | - branch: Evaluate variable       |
                         | - connect: Create outbound call   |
                         +-----------------------------------+
         |
         v
3. Process Result
+------------------+
| Execution Result |
+--------+---------+
         |
         +------------------+------------------+
         |                  |                  |
         v                  v                  v
+-------------+    +---------------+    +-------------+
| result_next |    | result_wait   |    | result_done |
| (continue)  |    | (async event) |    | (flow ends) |
+------+------+    +-------+-------+    +------+------+
       |                   |                   |
       v                   v                   v
Move cursor to      Keep cursor,         Mark activeflow
next action         wait for event       as ended

Action Execution Results

Each action executor returns one of these result types:

Action Result Types:

+------------------------------------------------------------------+
|                         result_next                              |
+------------------------------------------------------------------+
| Meaning: Action completed, move to next action immediately       |
| Used by: goto, branch, variable_set, condition_*, answer         |
|                                                                  |
| Flow continues without waiting:                                  |
| +-------+     +-------+     +-------+                           |
| | goto  |---->| talk  |---->| next  |                           |
| +-------+     +-------+     +-------+                           |
|     ^                                                            |
|     |                                                            |
|  result_next                                                     |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                         result_wait                              |
+------------------------------------------------------------------+
| Meaning: Action started async operation, wait for completion     |
| Used by: talk, play, digits_receive, connect, queue_join         |
|                                                                  |
| Execution pauses, waiting for event:                             |
| +-------+     +-----------------+     +-------+                  |
| | talk  |---->| (waiting...)    |---->| next  |                  |
| +-------+     | TTS playing     |     +-------+                  |
|               +-----------------+                                |
|                       ^                                          |
|                       |                                          |
|               Media complete event                               |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                         result_block                             |
+------------------------------------------------------------------+
| Meaning: Flow is blocked until external API call resumes it      |
| Used by: block                                                   |
|                                                                  |
| Execution stops until API trigger:                               |
| +-------+     +-------------------+     +-------+                |
| | block |---->| BLOCKED           |---->| next  |                |
| +-------+     | (waiting for API) |     +-------+                |
|               +-------------------+                              |
|                       ^                                          |
|                       |                                          |
|           POST /activeflows/{id}/execute                         |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                         result_done                              |
+------------------------------------------------------------------+
| Meaning: Flow execution is complete                              |
| Used by: stop, hangup (when call ends), end of actions           |
|                                                                  |
| Flow terminates:                                                 |
| +-------+     +-------+                                          |
| | stop  |---->| END   |                                          |
| +-------+     +-------+                                          |
+------------------------------------------------------------------+

Inter-Service Communication During Execution

Flow execution involves multiple services communicating via RabbitMQ:

Talk Action Execution Flow:

flow-manager          call-manager         asterisk-proxy        Asterisk
     |                     |                     |                   |
     | Execute talk        |                     |                   |
     | action              |                     |                   |
     |                     |                     |                   |
     |--(RPC)------------->|                     |                   |
     | TalkStart request   |                     |                   |
     |                     |                     |                   |
     |                     |--(RPC)------------->|                   |
     |                     | Media command       |                   |
     |                     |                     |                   |
     |                     |                     |--(ARI)----------->|
     |                     |                     | Play media        |
     |                     |                     |                   |
     |                     |                     |<-(Event)----------|
     |                     |                     | PlaybackFinished  |
     |                     |                     |                   |
     |                     |<-(Event)------------|                   |
     |                     | MediaComplete       |                   |
     |                     |                     |                   |
     |<-(Event)------------|                     |                   |
     | ActionComplete      |                     |                   |
     |                     |                     |                   |
     | Continue to         |                     |                   |
     | next action         |                     |                   |
Connect Action Execution Flow:

flow-manager          call-manager         asterisk-proxy        Asterisk
     |                     |                     |                   |
     | Execute connect     |                     |                   |
     |                     |                     |                   |
     |--(RPC)------------->|                     |                   |
     | Connect request     |                     |                   |
     | (destinations)      |                     |                   |
     |                     |                     |                   |
     |                     | Create outbound     |                   |
     |                     | call record         |                   |
     |                     |                     |                   |
     |                     |--(RPC)------------->|                   |
     |                     | Originate request   |                   |
     |                     |                     |                   |
     |                     |                     |--(ARI)----------->|
     |                     |                     | channels/create   |
     |                     |                     |                   |
     |                     |                     |<-(Event)----------|
     |                     |                     | ChannelCreated    |
     |                     |                     |                   |
     |                     |                     |<-(Event)----------|
     |                     |                     | ChannelAnswered   |
     |                     |                     |                   |
     |                     |<-(Event)------------|                   |
     |                     | CallAnswered        |                   |
     |                     |                     |                   |
     |                     | Bridge calls        |                   |
     |                     | together            |                   |
     |                     |                     |                   |
     |<-(Event)------------|                     |                   |
     | ConnectComplete     |                     |                   |
     |                     |                     |                   |
     | Flow waits for      |                     |                   |
     | call to end         |                     |                   |

Variable System Internals

Variables are stored and resolved during flow execution:

Variable Storage Architecture:

+------------------------------------------------------------------+
|                     Activeflow Variables                         |
+------------------------------------------------------------------+
|                                                                  |
| Storage: JSON column in activeflows table                        |
|                                                                  |
| {                                                                |
|   "voipbin.activeflow.id": "abc-123",                           |
|   "voipbin.activeflow.reference_id": "call-456",                |
|   "voipbin.call.id": "call-456",                                |
|   "voipbin.call.source.target": "+15551234567",                 |
|   "voipbin.call.destination.target": "+15559876543",            |
|   "voipbin.call.digits": "123",                                 |
|   "voipbin.call.status": "progressing",                         |
|   "voipbin.recording.id": "rec-789",                            |
|   "customer.tier": "premium",                 <- custom          |
|   "order.id": "ORD-12345"                     <- custom          |
| }                                                                |
|                                                                  |
+------------------------------------------------------------------+
Variable Resolution Process:

Input: "Hello ${customer.name}, your order ${order.id} is ready"

+------------------------------------------------------------------+
|                     Variable Resolver                            |
+------------------------------------------------------------------+

Step 1: Find all ${...} patterns
+------------------+
| Pattern scanner  |---> ["${customer.name}", "${order.id}"]
+------------------+

Step 2: Look up each variable
+------------------+     +------------------+
| customer.name    |---->| activeflow.vars  |---> "John Smith"
+------------------+     +------------------+

+------------------+     +------------------+
| order.id         |---->| activeflow.vars  |---> "ORD-12345"
+------------------+     +------------------+

Step 3: Substitute values
+------------------------------------------------------------------+
| Output: "Hello John Smith, your order ORD-12345 is ready"        |
+------------------------------------------------------------------+


Variable Set Timing:

+------------------------------------------------------------------+
| When Variables Are Set                                           |
+------------------------------------------------------------------+
|                                                                  |
| At activeflow creation:                                          |
|   - voipbin.activeflow.id                                        |
|   - voipbin.activeflow.reference_id                              |
|   - voipbin.activeflow.reference_type                            |
|                                                                  |
| When call starts:                                                |
|   - voipbin.call.id                                              |
|   - voipbin.call.source.target                                   |
|   - voipbin.call.destination.target                              |
|   - voipbin.call.direction                                       |
|                                                                  |
| After digits_receive action:                                     |
|   - voipbin.call.digits                                          |
|                                                                  |
| After recording_start action:                                    |
|   - voipbin.recording.id                                         |
|                                                                  |
| After transcribe completes:                                      |
|   - voipbin.transcribe.text                                      |
|                                                                  |
| By variable_set action:                                          |
|   - Any custom variable                                          |
+------------------------------------------------------------------+

Flow Forking and Stack Management

Nested flows use a stack-based execution model:

Flow Fork Mechanism:

Main Flow (stack depth 0)
+------------------------------------------------------------------+
| action 1: answer                                                 |
| action 2: talk "Welcome"                                         |
| action 3: queue_join  ----+                                      |
| action 4: talk "Goodbye"  |                                      |
+---------------------------|--------------------------------------+
                            |
                            | Fork creates new stack frame
                            v
Forked Flow (stack depth 1) - Wait Flow
+------------------------------------------------------------------+
| action 1: talk "Please hold..."                                  |
| action 2: play music.mp3                                         |
| action 3: goto action 1 (loop)                                   |
+------------------------------------------------------------------+
                            |
                            | When queue_join completes
                            | (agent answers or caller hangs up)
                            v
Returns to Main Flow
+------------------------------------------------------------------+
| action 4: talk "Goodbye"  <-- continues here                     |
+------------------------------------------------------------------+
Stack Frame Storage:

Activeflow record during nested execution:

+------------------------------------------------------------------+
| Main Activeflow                                                  |
+------------------------------------------------------------------+
| id: "main-af-123"                                                |
| current_action_id: "queue-join-action"                           |
| status: "executing"                                              |
| stack_depth: 0                                                   |
| forward_action_id: "goodbye-action"  <- return point             |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
| Forked Activeflow (Wait Flow)                                    |
+------------------------------------------------------------------+
| id: "forked-af-456"                                              |
| parent_activeflow_id: "main-af-123"                              |
| current_action_id: "play-music-action"                           |
| status: "executing"                                              |
| stack_depth: 1                                                   |
+------------------------------------------------------------------+

Event-Driven Execution

Many actions wait for external events to continue:

Event Types and Sources:

+------------------------------------------------------------------+
|                     Event Processing                             |
+------------------------------------------------------------------+

Media Events (from Asterisk via asterisk-proxy):
+----------------------+------------------------------------------+
| Event                | Triggers                                 |
+----------------------+------------------------------------------+
| PlaybackFinished     | talk/play action completion              |
| DTMFReceived         | digits_receive completion                |
| RecordingFinished    | recording_stop or silence/timeout        |
+----------------------+------------------------------------------+

Call Events (from call-manager):
+----------------------+------------------------------------------+
| Event                | Triggers                                 |
+----------------------+------------------------------------------+
| CallAnswered         | connect action (destination answered)    |
| CallHangup           | Flow termination                         |
| BridgeDestroyed      | connect completion (party disconnected)  |
+----------------------+------------------------------------------+

Queue Events (from queue-manager):
+----------------------+------------------------------------------+
| Event                | Triggers                                 |
+----------------------+------------------------------------------+
| AgentAnswered        | queue_join completion (success)          |
| QueueTimeout         | queue_join completion (timeout)          |
| QueueEmpty           | queue_join completion (no agents)        |
+----------------------+------------------------------------------+

AI Events (from ai-manager):
+----------------------+------------------------------------------+
| Event                | Triggers                                 |
+----------------------+------------------------------------------+
| AITalkComplete       | ai_talk completion                       |
| TranscribeResult     | Real-time transcription result           |
+----------------------+------------------------------------------+
Event Routing to Activeflow:

+------------------------------------------------------------------+
|                     Event Router                                 |
+------------------------------------------------------------------+

1. Event arrives at flow-manager
+------------------+
| RabbitMQ Event   |
| {                |
|   type: "media"  |
|   call_id: "xyz" |
|   event: "done"  |
| }                |
+--------+---------+
         |
         v
2. Look up activeflow by reference_id
+------------------+
| SELECT * FROM    |
| activeflows      |
| WHERE ref_id =   |
| "xyz"            |
+--------+---------+
         |
         v
3. Resume execution
+------------------+
| Execute next     |
| action           |
+------------------+

Safety Mechanisms

VoIPBIN includes safeguards to prevent runaway flows:

Execution Limits:

+------------------------------------------------------------------+
|                     Safety Counters                              |
+------------------------------------------------------------------+

Per-Cycle Iteration Limit:
+------------------------------------------+
| Max iterations: 1000                     |
| Counted: Each action in one cycle        |
| Reset: When flow waits for async event   |
+------------------------------------------+

Example:
+-------+  +-------+  +-------+     +-------+
| goto  |->| goto  |->| goto  |...->| ERROR |
+-------+  +-------+  +-------+     +-------+
   1          2          3    ...    1000
                               (stops here)

Total Execution Limit:
+------------------------------------------+
| Max total executions: 100                |
| Counted: Each time flow resumes          |
| Never reset during activeflow lifetime   |
+------------------------------------------+

Example:
Call with 100 DTMF interactions would hit this limit

On-Complete Chain Limit:
+------------------------------------------+
| Max chain depth: 5                       |
| Counted: on_complete_flow_id triggers    |
+------------------------------------------+

Flow A -> Flow B -> Flow C -> Flow D -> Flow E -> STOP
  0         1         2         3         4        5(blocked)
Loop Detection:

Goto Loop Counter:
+------------------------------------------------------------------+
| The goto action has a built-in loop_count parameter              |
|                                                                  |
| {                                                                |
|   "type": "goto",                                                |
|   "option": {                                                    |
|     "target_id": "action-123",                                   |
|     "loop_count": 3   <- Maximum times to execute this goto     |
|   }                                                              |
| }                                                                |
|                                                                  |
| Execution:                                                       |
| Loop 1: goto -> action-123                                       |
| Loop 2: goto -> action-123                                       |
| Loop 3: goto -> action-123                                       |
| Loop 4: goto SKIPPED -> continue to next action                  |
+------------------------------------------------------------------+

Concurrent Execution Handling

Multiple events can arrive for the same activeflow:

Concurrency Control:

+------------------------------------------------------------------+
|                     Execution Locking                            |
+------------------------------------------------------------------+

Problem: Two events arrive simultaneously
+-------------+                    +-------------+
| Event A:    |                    | Event B:    |
| DTMF "1"    |                    | Timeout     |
+------+------+                    +------+------+
       |                                  |
       v                                  v
+------------------------------------------------------------------+
|           Both try to resume activeflow                          |
+------------------------------------------------------------------+

Solution: Database-level locking
+------------------------------------------------------------------+
| 1. Transaction starts                                            |
| 2. SELECT ... FOR UPDATE on activeflow                           |
| 3. Check current status                                          |
| 4. Process event if valid                                        |
| 5. Update status and cursor                                      |
| 6. Commit transaction                                            |
+------------------------------------------------------------------+

Result:
- Event A wins (arrives first, gets lock)
- Event B sees activeflow already moved
- Event B is discarded as stale

RabbitMQ Message Patterns

Flow-manager uses specific message patterns:

Queue Names:

+------------------------------------------------------------------+
| bin-manager.flow-manager.request                                 |
| - Incoming RPC requests (create activeflow, execute, stop)       |
+------------------------------------------------------------------+
| bin-manager.flow-manager.event                                   |
| - Incoming events (media complete, call hangup, etc.)            |
+------------------------------------------------------------------+


Request Message Format:
+------------------------------------------------------------------+
| {                                                                |
|   "uri": "/v1/activeflows",                                      |
|   "method": "POST",                                              |
|   "data": {                                                      |
|     "flow_id": "flow-123",                                       |
|     "reference_type": "call",                                    |
|     "reference_id": "call-456"                                   |
|   }                                                              |
| }                                                                |
+------------------------------------------------------------------+


Event Message Format:
+------------------------------------------------------------------+
| {                                                                |
|   "type": "call",                                                |
|   "event": "hangup",                                             |
|   "reference_id": "call-456",                                    |
|   "data": {                                                      |
|     "hangup_cause": "normal_clearing"                            |
|   }                                                              |
| }                                                                |
+------------------------------------------------------------------+

Database Schema

Key tables involved in flow execution:

flows table:
+------------------------------------------------------------------+
| Column               | Type          | Description               |
+----------------------+---------------+---------------------------+
| id                   | uuid          | Flow definition ID        |
| customer_id          | uuid          | Owner                     |
| name                 | varchar(255)  | Display name              |
| detail               | text          | Description               |
| actions              | json          | Array of action objects   |
| on_complete_flow_id  | uuid          | Chain to next flow        |
| tm_create            | datetime      | Created timestamp         |
| tm_update            | datetime      | Updated timestamp         |
| tm_delete            | datetime      | Soft delete timestamp     |
+------------------------------------------------------------------+

activeflows table:
+------------------------------------------------------------------+
| Column               | Type          | Description               |
+----------------------+---------------+---------------------------+
| id                   | uuid          | Activeflow instance ID    |
| customer_id          | uuid          | Owner                     |
| flow_id              | uuid          | Flow definition reference |
| reference_type       | varchar(32)   | "call", "message", "api"  |
| reference_id         | uuid          | Associated resource ID    |
| current_action_id    | uuid          | Cursor position           |
| status               | varchar(32)   | Execution state           |
| variables            | json          | Runtime variables         |
| forward_action_id    | uuid          | Return point for forks    |
| parent_activeflow_id | uuid          | Parent for nested flows   |
| stack_depth          | int           | Nesting level             |
| execute_count        | int           | Safety counter            |
| complete_count       | int           | On-complete chain counter |
| tm_create            | datetime      | Created timestamp         |
| tm_update            | datetime      | Last execution timestamp  |
| tm_end               | datetime      | Completion timestamp      |
+------------------------------------------------------------------+

Advanced Flow Patterns

This section covers advanced flow design patterns for building sophisticated communication applications.

Multi-Level IVR with Sub-Menus

Building complex IVR systems with nested menus:

Multi-Level IVR Structure:

                          Main Menu
                              |
        +---------------------+---------------------+
        |                     |                     |
     Press 1              Press 2              Press 3
     Sales                Support              Billing
        |                     |                     |
    +---+---+             +---+---+             +---+---+
    |       |             |       |             |       |
  Press 1 Press 2      Press 1 Press 2      Press 1 Press 2
  New     Existing     Tech    Account     Payment  Disputes
  Customer Customer    Support Support     Info

Implementation Strategy:
+------------------------------------------------------------------+
| Use fetch_flow to load sub-menus dynamically                     |
| This keeps each flow focused and maintainable                    |
+------------------------------------------------------------------+
Main Menu Flow:

{
  "name": "Main IVR Menu",
  "actions": [
    {
      "id": "main-answer",
      "type": "answer"
    },
    {
      "id": "main-greeting",
      "type": "talk",
      "option": {
        "text": "Welcome to Acme Corp. Press 1 for Sales, 2 for Support, 3 for Billing.",
        "language": "en-US"
      }
    },
    {
      "id": "main-input",
      "type": "digits_receive",
      "option": {
        "duration": 5000,
        "length": 1
      }
    },
    {
      "id": "main-branch",
      "type": "branch",
      "option": {
        "variable": "voipbin.call.digits",
        "default_target_id": "invalid-input",
        "target_ids": {
          "1": "goto-sales",
          "2": "goto-support",
          "3": "goto-billing"
        }
      }
    },
    {
      "id": "goto-sales",
      "type": "fetch_flow",
      "option": {
        "flow_id": "sales-submenu-flow-id"
      }
    },
    {
      "id": "goto-support",
      "type": "fetch_flow",
      "option": {
        "flow_id": "support-submenu-flow-id"
      }
    },
    {
      "id": "goto-billing",
      "type": "fetch_flow",
      "option": {
        "flow_id": "billing-submenu-flow-id"
      }
    },
    {
      "id": "invalid-input",
      "type": "talk",
      "option": {
        "text": "Invalid selection.",
        "language": "en-US"
      }
    },
    {
      "id": "retry-goto",
      "type": "goto",
      "option": {
        "target_id": "main-greeting",
        "loop_count": 3
      }
    },
    {
      "type": "talk",
      "option": {
        "text": "Goodbye.",
        "language": "en-US"
      }
    },
    {
      "type": "hangup"
    }
  ]
}

Business Hours Routing

Route calls differently based on time of day:

Business Hours Flow:

                       Incoming Call
                            |
                            v
                +---------------------+
                | condition_datetime  |
                | (9 AM - 5 PM,       |
                |  Mon-Fri)           |
                +----------+----------+
                           |
          +----------------+----------------+
          |                                 |
     During Hours                    After Hours
          |                                 |
          v                                 v
+------------------+              +------------------+
| queue_join       |              | Voicemail Flow   |
| (live agents)    |              | (leave message)  |
+------------------+              +------------------+
{
  "name": "Business Hours Router",
  "actions": [
    {
      "type": "answer"
    },
    {
      "id": "check-hours",
      "type": "condition_datetime",
      "option": {
        "condition": ">=",
        "hour": 9,
        "minute": 0,
        "day": -1,
        "month": 0,
        "weekdays": [1, 2, 3, 4, 5],
        "false_target_id": "after-hours"
      }
    },
    {
      "id": "check-closing",
      "type": "condition_datetime",
      "option": {
        "condition": "<",
        "hour": 17,
        "minute": 0,
        "day": -1,
        "month": 0,
        "weekdays": [1, 2, 3, 4, 5],
        "false_target_id": "after-hours"
      }
    },
    {
      "id": "during-hours",
      "type": "talk",
      "option": {
        "text": "Thank you for calling. Connecting you to an agent.",
        "language": "en-US"
      }
    },
    {
      "type": "queue_join",
      "option": {
        "queue_id": "support-queue-id"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "after-hours",
      "type": "talk",
      "option": {
        "text": "Our office is currently closed. Our hours are Monday through Friday, 9 AM to 5 PM. Please leave a message after the tone.",
        "language": "en-US"
      }
    },
    {
      "type": "beep"
    },
    {
      "type": "recording_start",
      "option": {
        "format": "mp3",
        "end_of_silence": 5,
        "duration": 120
      }
    },
    {
      "type": "talk",
      "option": {
        "text": "Thank you for your message. Goodbye.",
        "language": "en-US"
      }
    },
    {
      "type": "hangup"
    }
  ]
}

Dynamic Flow with External Data

Fetch customer data from your API to personalize the experience:

External Data Integration:

+------------------------------------------------------------------+
|                     Dynamic Flow Pattern                         |
+------------------------------------------------------------------+

1. Call arrives
+----------------+
| answer         |
+----------------+
       |
       v
2. Fetch customer data from your API
+----------------+     +---------------------------+
| fetch          |---->| Your API:                 |
| (sync: true)   |     | GET /customers?phone=...  |
+----------------+     +---------------------------+
       |                          |
       |     Response: {"name": "John", "tier": "premium"}
       |                          |
       v                          v
3. Variables are set from response
+------------------------------------------+
| customer.name = "John"                   |
| customer.tier = "premium"                |
+------------------------------------------+
       |
       v
4. Personalize the flow
+------------------------------------------+
| talk: "Hello ${customer.name}..."        |
| branch on ${customer.tier}               |
+------------------------------------------+
Implementation with webhook_send:

{
  "name": "Personalized Greeting",
  "actions": [
    {
      "type": "answer"
    },
    {
      "id": "fetch-customer",
      "type": "webhook_send",
      "option": {
        "sync": true,
        "uri": "https://your-api.com/customer-lookup",
        "method": "POST",
        "data_type": "application/json",
        "data": "{\"phone\": \"${voipbin.call.source.target}\"}"
      }
    },
    {
      "type": "talk",
      "option": {
        "text": "Hello ${customer.name}. Welcome back to our service.",
        "language": "en-US"
      }
    },
    {
      "id": "tier-check",
      "type": "branch",
      "option": {
        "variable": "customer.tier",
        "default_target_id": "standard-service",
        "target_ids": {
          "premium": "premium-service",
          "vip": "vip-service"
        }
      }
    },
    {
      "id": "premium-service",
      "type": "talk",
      "option": {
        "text": "As a premium member, you're being connected to our priority support line.",
        "language": "en-US"
      }
    },
    {
      "type": "queue_join",
      "option": {
        "queue_id": "premium-queue-id"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "vip-service",
      "type": "connect",
      "option": {
        "source": {
          "type": "tel",
          "target": "${voipbin.call.destination.target}"
        },
        "destinations": [
          {
            "type": "tel",
            "target": "+15551234567"
          }
        ]
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "standard-service",
      "type": "talk",
      "option": {
        "text": "Please hold while we connect you.",
        "language": "en-US"
      }
    },
    {
      "type": "queue_join",
      "option": {
        "queue_id": "standard-queue-id"
      }
    },
    {
      "type": "hangup"
    }
  ]
}

AI-Powered Conversational Flow

Integrate AI for natural language interactions:

AI Voice Assistant Pattern:

+------------------------------------------------------------------+
|                     AI Talk Integration                          |
+------------------------------------------------------------------+

Traditional IVR:
+-------+     +----------+     +--------+     +---------+
| talk  |---->| digits   |---->| branch |---->| action  |
| menu  |     | receive  |     | 1,2,3  |     |         |
+-------+     +----------+     +--------+     +---------+

AI-Powered:
+-------+     +----------+     +----------+     +---------+
| ai    |---->| AI       |---->| Intent   |---->| action  |
| talk  |     | processes|     | detected |     |         |
+-------+     | speech   |     | routing  |     +---------+
              +----------+     +----------+

AI Talk handles:
- Speech recognition (STT)
- Natural language understanding
- Response generation
- Text-to-speech (TTS)
- Context maintenance
AI Talk Flow Example:

{
  "name": "AI Customer Service",
  "actions": [
    {
      "type": "answer"
    },
    {
      "id": "ai-greeting",
      "type": "ai_talk",
      "option": {
        "ai_id": "your-ai-agent-id",
        "language": "en-US",
        "gender": "female",
        "duration": 300
      }
    },
    {
      "id": "post-ai-branch",
      "type": "branch",
      "option": {
        "variable": "voipbin.ai.intent",
        "default_target_id": "transfer-support",
        "target_ids": {
          "billing": "transfer-billing",
          "technical": "transfer-technical",
          "cancel": "transfer-retention",
          "resolved": "goodbye"
        }
      }
    },
    {
      "id": "transfer-billing",
      "type": "talk",
      "option": {
        "text": "I'll transfer you to our billing department.",
        "language": "en-US"
      }
    },
    {
      "type": "queue_join",
      "option": {
        "queue_id": "billing-queue-id"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "transfer-technical",
      "type": "queue_join",
      "option": {
        "queue_id": "tech-support-queue-id"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "transfer-retention",
      "type": "queue_join",
      "option": {
        "queue_id": "retention-queue-id"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "transfer-support",
      "type": "queue_join",
      "option": {
        "queue_id": "general-support-queue-id"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "goodbye",
      "type": "talk",
      "option": {
        "text": "Thank you for calling. Have a great day!",
        "language": "en-US"
      }
    },
    {
      "type": "hangup"
    }
  ]
}

Callback Request Pattern

Allow customers to request a callback instead of waiting:

Callback Flow Pattern:

+------------------------------------------------------------------+
|                     Callback Request                             |
+------------------------------------------------------------------+

                Incoming Call
                      |
                      v
+---------------------------------------------------+
| "All agents are busy. Press 1 to wait on hold,    |
|  or press 2 to receive a callback."               |
+---------------------------------------------------+
                      |
        +-------------+-------------+
        |                           |
     Press 1                     Press 2
     (wait)                      (callback)
        |                           |
        v                           v
+--------------+            +---------------+
| queue_join   |            | Confirm phone |
+--------------+            +---------------+
                                    |
                                    v
                            +---------------+
                            | webhook_send  |
                            | (create task) |
                            +---------------+
                                    |
                                    v
                            +---------------+
                            | "We will call |
                            |  you back"    |
                            +---------------+
                                    |
                                    v
                                hangup
{
  "name": "Callback Option Flow",
  "actions": [
    {
      "type": "answer"
    },
    {
      "id": "callback-offer",
      "type": "talk",
      "option": {
        "text": "All of our agents are currently busy. Your estimated wait time is 10 minutes. Press 1 to wait on hold, or press 2 to receive a callback when an agent is available.",
        "language": "en-US"
      }
    },
    {
      "type": "digits_receive",
      "option": {
        "duration": 10000,
        "length": 1
      }
    },
    {
      "type": "branch",
      "option": {
        "variable": "voipbin.call.digits",
        "default_target_id": "callback-offer",
        "target_ids": {
          "1": "wait-queue",
          "2": "request-callback"
        }
      }
    },
    {
      "id": "wait-queue",
      "type": "talk",
      "option": {
        "text": "Please hold. An agent will be with you shortly.",
        "language": "en-US"
      }
    },
    {
      "type": "queue_join",
      "option": {
        "queue_id": "support-queue-id"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "request-callback",
      "type": "talk",
      "option": {
        "text": "We will call you back at the number you called from. If you'd like to be called at a different number, please enter it now followed by the pound key. Otherwise, press pound to confirm.",
        "language": "en-US"
      }
    },
    {
      "type": "digits_receive",
      "option": {
        "duration": 15000,
        "length": 15,
        "key": "#"
      }
    },
    {
      "id": "check-digits",
      "type": "condition_variable",
      "option": {
        "condition": "==",
        "variable": "voipbin.call.digits",
        "value_type": "string",
        "value_string": "#",
        "false_target_id": "custom-number"
      }
    },
    {
      "type": "variable_set",
      "option": {
        "key": "callback.number",
        "value": "${voipbin.call.source.target}"
      }
    },
    {
      "id": "schedule-callback",
      "type": "webhook_send",
      "option": {
        "sync": true,
        "uri": "https://your-api.com/schedule-callback",
        "method": "POST",
        "data_type": "application/json",
        "data": "{\"phone\": \"${callback.number}\", \"call_id\": \"${voipbin.call.id}\"}"
      }
    },
    {
      "type": "talk",
      "option": {
        "text": "Thank you. You will receive a callback at ${callback.number} within the next 30 minutes. Goodbye.",
        "language": "en-US"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "custom-number",
      "type": "variable_set",
      "option": {
        "key": "callback.number",
        "value": "${voipbin.call.digits}"
      }
    },
    {
      "type": "goto",
      "option": {
        "target_id": "schedule-callback"
      }
    }
  ]
}

Survey After Call

Using on_complete_flow_id for post-call surveys:

Post-Call Survey Pattern:

+------------------------------------------------------------------+
|                     Main Call Flow                               |
+------------------------------------------------------------------+
| answer -> talk -> queue_join -> hangup                           |
|                                                                  |
| on_complete_flow_id: "survey-flow-id"                           |
+------------------------------------------------------------------+
                      |
                      | (call ends)
                      v
+------------------------------------------------------------------+
|                     Survey Flow                                  |
+------------------------------------------------------------------+
| (New session, inherits variables)                                |
|                                                                  |
| Create outbound call to customer                                 |
| -> Play survey questions                                         |
| -> Collect responses                                             |
| -> Send results to webhook                                       |
+------------------------------------------------------------------+
Main Call Flow (with on_complete_flow_id):

{
  "name": "Support Call",
  "on_complete_flow_id": "post-call-survey-flow-id",
  "actions": [
    {
      "type": "answer"
    },
    {
      "type": "recording_start",
      "option": {
        "format": "mp3"
      }
    },
    {
      "type": "queue_join",
      "option": {
        "queue_id": "support-queue-id"
      }
    },
    {
      "type": "hangup"
    }
  ]
}

Survey Flow (executed after call ends):

{
  "name": "Post-Call Survey",
  "actions": [
    {
      "type": "call",
      "option": {
        "source": {
          "type": "tel",
          "target": "+15551234567"
        },
        "destinations": [
          {
            "type": "tel",
            "target": "${voipbin.call.source.target}"
          }
        ],
        "actions": [
          {
            "type": "talk",
            "option": {
              "text": "Thank you for contacting us. Please help us improve by answering a brief survey. On a scale of 1 to 5, how satisfied were you with your support experience? Press 1 for very unsatisfied, 5 for very satisfied.",
              "language": "en-US"
            }
          },
          {
            "type": "digits_receive",
            "option": {
              "duration": 10000,
              "length": 1
            }
          },
          {
            "type": "variable_set",
            "option": {
              "key": "survey.satisfaction",
              "value": "${voipbin.call.digits}"
            }
          },
          {
            "type": "talk",
            "option": {
              "text": "Was your issue resolved? Press 1 for yes, 2 for no.",
              "language": "en-US"
            }
          },
          {
            "type": "digits_receive",
            "option": {
              "duration": 10000,
              "length": 1
            }
          },
          {
            "type": "variable_set",
            "option": {
              "key": "survey.resolved",
              "value": "${voipbin.call.digits}"
            }
          },
          {
            "type": "webhook_send",
            "option": {
              "uri": "https://your-api.com/survey-results",
              "method": "POST",
              "data_type": "application/json",
              "data": "{\"call_id\": \"${voipbin.call.id}\", \"satisfaction\": \"${survey.satisfaction}\", \"resolved\": \"${survey.resolved}\"}"
            }
          },
          {
            "type": "talk",
            "option": {
              "text": "Thank you for your feedback. Goodbye.",
              "language": "en-US"
            }
          },
          {
            "type": "hangup"
          }
        ]
      }
    }
  ]
}

Failover and Redundancy

Handle failures gracefully with fallback options:

Failover Pattern:

+------------------------------------------------------------------+
|                     Multi-Destination Failover                   |
+------------------------------------------------------------------+

Primary:     connect to Agent 1
                   |
             +-----------+
             | answered? |
             +-----+-----+
                   |
        +----------+----------+
        |                     |
       Yes                   No
        |                     |
        v                     v
+-------------+       Secondary: connect to Agent 2
| Continue    |               |
+-------------+         +-----------+
                        | answered? |
                        +-----+-----+
                              |
                   +----------+----------+
                   |                     |
                  Yes                   No
                   |                     |
                   v                     v
           +-------------+       Tertiary: connect to Queue
           | Continue    |               |
           +-------------+               v
                                 +-------------+
                                 | queue_join  |
                                 +-------------+
{
  "name": "Failover Flow",
  "actions": [
    {
      "type": "answer"
    },
    {
      "type": "talk",
      "option": {
        "text": "Please hold while we connect you.",
        "language": "en-US"
      }
    },
    {
      "id": "try-primary",
      "type": "connect",
      "option": {
        "source": {
          "type": "tel",
          "target": "+15551234567"
        },
        "destinations": [
          {
            "type": "tel",
            "target": "+15559876543"
          }
        ]
      }
    },
    {
      "type": "condition_variable",
      "option": {
        "condition": "==",
        "variable": "voipbin.call.status",
        "value_type": "string",
        "value_string": "progressing",
        "false_target_id": "try-secondary"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "try-secondary",
      "type": "talk",
      "option": {
        "text": "Agent unavailable. Trying alternate contact.",
        "language": "en-US"
      }
    },
    {
      "type": "connect",
      "option": {
        "source": {
          "type": "tel",
          "target": "+15551234567"
        },
        "destinations": [
          {
            "type": "tel",
            "target": "+15551112222"
          }
        ]
      }
    },
    {
      "type": "condition_variable",
      "option": {
        "condition": "==",
        "variable": "voipbin.call.status",
        "value_type": "string",
        "value_string": "progressing",
        "false_target_id": "try-queue"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "try-queue",
      "type": "talk",
      "option": {
        "text": "All direct contacts unavailable. Placing you in the support queue.",
        "language": "en-US"
      }
    },
    {
      "type": "queue_join",
      "option": {
        "queue_id": "support-queue-id"
      }
    },
    {
      "type": "hangup"
    }
  ]
}

Language Selection

Multi-language IVR with persistent language preference:

Language Selection Pattern:

+------------------------------------------------------------------+
|                     Language Router                              |
+------------------------------------------------------------------+

                Incoming Call
                      |
                      v
+---------------------------------------------------+
| "For English, press 1. Para Espanol, marque 2.    |
|  Pour Francais, appuyez 3."                       |
+---------------------------------------------------+
                      |
        +-------------+-------------+
        |             |             |
     Press 1       Press 2       Press 3
     English       Spanish       French
        |             |             |
        v             v             v
+------------+ +------------+ +------------+
| Set lang:  | | Set lang:  | | Set lang:  |
| en-US      | | es-ES      | | fr-FR      |
+------------+ +------------+ +------------+
        |             |             |
        +-------------+-------------+
                      |
                      v
              Main Flow (uses
              ${language} variable)
{
  "name": "Multi-Language IVR",
  "actions": [
    {
      "type": "answer"
    },
    {
      "id": "lang-prompt",
      "type": "talk",
      "option": {
        "text": "<speak><lang xml:lang='en-US'>For English, press 1.</lang> <lang xml:lang='es-ES'>Para Espanol, marque 2.</lang> <lang xml:lang='fr-FR'>Pour Francais, appuyez 3.</lang></speak>",
        "language": "en-US"
      }
    },
    {
      "type": "digits_receive",
      "option": {
        "duration": 5000,
        "length": 1
      }
    },
    {
      "type": "branch",
      "option": {
        "variable": "voipbin.call.digits",
        "default_target_id": "set-english",
        "target_ids": {
          "1": "set-english",
          "2": "set-spanish",
          "3": "set-french"
        }
      }
    },
    {
      "id": "set-english",
      "type": "variable_set",
      "option": {
        "key": "language",
        "value": "en-US"
      }
    },
    {
      "type": "goto",
      "option": {
        "target_id": "main-menu"
      }
    },
    {
      "id": "set-spanish",
      "type": "variable_set",
      "option": {
        "key": "language",
        "value": "es-ES"
      }
    },
    {
      "type": "goto",
      "option": {
        "target_id": "main-menu"
      }
    },
    {
      "id": "set-french",
      "type": "variable_set",
      "option": {
        "key": "language",
        "value": "fr-FR"
      }
    },
    {
      "type": "goto",
      "option": {
        "target_id": "main-menu"
      }
    },
    {
      "id": "main-menu",
      "type": "fetch_flow",
      "option": {
        "flow_id": "main-menu-flow-id"
      }
    }
  ]
}


Main Menu Flow (uses language variable):

{
  "name": "Main Menu",
  "actions": [
    {
      "type": "talk",
      "option": {
        "text": "Welcome to our service. Press 1 for sales, 2 for support.",
        "language": "${language}"
      }
    }
  ]
}

Parallel Call Attempts (Ring All)

Ring multiple destinations simultaneously:

Ring All Pattern:

+------------------------------------------------------------------+
|                     Parallel Ring                                |
+------------------------------------------------------------------+

                Incoming Call
                      |
                      v
                +-----------+
                |  Connect  |
                | (multiple |
                |  dests)   |
                +-----------+
                      |
        +-------------+-------------+
        |             |             |
     Agent 1       Agent 2       Agent 3
     ringing       ringing       ringing
        |             |             |
        +------+------+             |
               |                    |
               | First to answer    |
               | wins               |
               v                    v
        +-----------+         +-----------+
        | Connected |         | Cancelled |
        +-----------+         +-----------+
{
  "name": "Ring All Flow",
  "actions": [
    {
      "type": "answer"
    },
    {
      "type": "talk",
      "option": {
        "text": "Please hold while we connect you to the next available agent.",
        "language": "en-US"
      }
    },
    {
      "type": "connect",
      "option": {
        "source": {
          "type": "tel",
          "target": "+15551234567"
        },
        "destinations": [
          {
            "type": "tel",
            "target": "+15559876543"
          },
          {
            "type": "tel",
            "target": "+15551112222"
          },
          {
            "type": "tel",
            "target": "+15553334444"
          }
        ],
        "early_media": true
      }
    },
    {
      "type": "hangup"
    }
  ]
}

Real-Time Transcription with Keyword Detection

Monitor calls for specific keywords:

Transcription Pattern:

+------------------------------------------------------------------+
|                     Keyword Monitoring                           |
+------------------------------------------------------------------+

                Incoming Call
                      |
                      v
                +-----------+
                | Start     |
                | transcribe|
                +-----------+
                      |
                      v
                +-----------+
                | Connect   |
                | to agent  |
                +-----------+
                      |
                      |  Transcripts sent to webhook
                      |  in real-time
                      v
+---------------------------------------------------+
| Your API monitors for keywords:                   |
| - "cancel subscription" -> Alert retention team   |
| - "legal action" -> Alert legal team              |
| - "supervisor" -> Trigger escalation              |
+---------------------------------------------------+
{
  "name": "Transcribed Call Flow",
  "actions": [
    {
      "type": "answer"
    },
    {
      "type": "transcribe_start",
      "option": {
        "language": "en-US"
      }
    },
    {
      "type": "talk",
      "option": {
        "text": "This call is being transcribed for quality assurance. Connecting you now.",
        "language": "en-US"
      }
    },
    {
      "type": "queue_join",
      "option": {
        "queue_id": "support-queue-id"
      }
    },
    {
      "type": "transcribe_stop"
    },
    {
      "type": "hangup"
    }
  ]
}

Flow Debugging and Troubleshooting

This section provides tools and techniques for debugging flow execution issues.

Debugging Tools

VoIPBIN provides several tools for debugging flows:

Available Debugging Resources:

+------------------------------------------------------------------+
|                     API Endpoints                                |
+------------------------------------------------------------------+
| GET /v1/activeflows                                              |
|   List all activeflow instances for your account                 |
|                                                                  |
| GET /v1/activeflows/{id}                                         |
|   Get detailed state of a specific activeflow                    |
|                                                                  |
| GET /v1/activeflows/{id}/variables                               |
|   Get current variables for an activeflow                        |
|                                                                  |
| GET /v1/calls/{id}                                               |
|   Get call details including flow execution status               |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                     Webhooks                                     |
+------------------------------------------------------------------+
| activeflow.created     | When a new activeflow starts            |
| activeflow.updated     | When activeflow state changes           |
| activeflow.deleted     | When activeflow ends                    |
| call.progressing       | Call state updates during flow          |
+------------------------------------------------------------------+

Examining Activeflow State

Use the API to inspect activeflow execution:

Get Activeflow Details:

Request:
GET /v1/activeflows/abc-123-def

Response:
{
  "id": "abc-123-def",
  "customer_id": "cust-456",
  "flow_id": "flow-789",
  "reference_type": "call",
  "reference_id": "call-xyz",
  "status": "executing",
  "current_action_id": "action-456",
  "execute_count": 5,
  "variables": {
    "voipbin.call.digits": "2",
    "voipbin.call.source.target": "+15551234567",
    "customer.name": "John"
  },
  "tm_create": "2024-01-15T10:30:00Z",
  "tm_update": "2024-01-15T10:30:45Z"
}

Key fields to examine:
+------------------------------------------------------------------+
| status             | Is the flow executing, waiting, or ended?  |
| current_action_id  | Which action is the cursor pointing to?    |
| execute_count      | How many times has the flow executed?      |
| variables          | What variables have been set?              |
+------------------------------------------------------------------+

Common Issues and Solutions

Flow Never Starts

Problem: Call connects but no flow actions execute

Diagnostic Steps:
+------------------------------------------------------------------+
| 1. Check if flow is attached to the number                       |
|    GET /v1/numbers/{number-id}                                   |
|    Look for: flow_id field                                       |
+------------------------------------------------------------------+
| 2. Check if activeflow was created                               |
|    GET /v1/activeflows?reference_id={call-id}                    |
|    If empty: flow failed to start                                |
+------------------------------------------------------------------+
| 3. Check flow definition exists                                  |
|    GET /v1/flows/{flow-id}                                       |
|    If 404: flow was deleted                                      |
+------------------------------------------------------------------+

Common Causes:
+------------------------------------------------------------------+
| - Number not linked to a flow                                    |
| - Flow ID is invalid or deleted                                  |
| - Flow actions array is empty                                    |
| - Customer billing issue blocking execution                      |
+------------------------------------------------------------------+

Flow Stops Unexpectedly

Problem: Flow stops in the middle without completing

Diagnostic Steps:
+------------------------------------------------------------------+
| 1. Check activeflow status                                       |
|    GET /v1/activeflows/{id}                                      |
|    Look at: status and current_action_id                         |
+------------------------------------------------------------------+
| 2. Check call status                                             |
|    GET /v1/calls/{call-id}                                       |
|    If hangup_reason present: call ended                          |
+------------------------------------------------------------------+
| 3. Check execute_count                                           |
|    If near 100: hit execution limit                              |
+------------------------------------------------------------------+

Common Causes:
+------------------------------------------------------------------+
| - Caller hung up (check call.hangup_reason)                      |
| - Hit execution limit (check execute_count)                      |
| - Invalid action in flow (skipped, flow ended)                   |
| - Infinite loop triggered safety stop                            |
+------------------------------------------------------------------+

Branch Not Working

Problem: Branch always goes to default or wrong target

Diagnostic Steps:
+------------------------------------------------------------------+
| 1. Check the variable value                                      |
|    GET /v1/activeflows/{id}/variables                            |
|    Look at: the variable used in branch                          |
+------------------------------------------------------------------+
| 2. Compare with branch targets                                   |
|    The value must EXACTLY match a target_ids key                 |
+------------------------------------------------------------------+

Example Debug:
+------------------------------------------------------------------+
| Branch action:                                                   |
| {                                                                |
|   "type": "branch",                                              |
|   "option": {                                                    |
|     "variable": "voipbin.call.digits",                           |
|     "target_ids": {                                              |
|       "1": "action-a",                                           |
|       "2": "action-b"                                            |
|     }                                                            |
|   }                                                              |
| }                                                                |
|                                                                  |
| Variable value: "1#"                                             |
|                                                                  |
| Problem: "1#" != "1"                                             |
| The # terminator was included in the digit string                |
+------------------------------------------------------------------+

Common Causes:
+------------------------------------------------------------------+
| - Variable contains extra characters (whitespace, terminators)   |
| - Variable name is misspelled                                    |
| - Variable was never set (action didn't execute)                 |
| - Case sensitivity (variable values are case-sensitive)          |
+------------------------------------------------------------------+

Talk Action Not Playing

Problem: Talk action executes but no audio heard

Diagnostic Steps:
+------------------------------------------------------------------+
| 1. Check call state when talk executes                           |
|    Call must be "progressing" (answered)                         |
+------------------------------------------------------------------+
| 2. Check if answer action came before talk                       |
|    For inbound calls, must answer first                          |
+------------------------------------------------------------------+
| 3. Check language parameter                                      |
|    Must be valid BCP47 code (en-US, not english)                 |
+------------------------------------------------------------------+

Common Causes:
+------------------------------------------------------------------+
| - Missing "answer" action before "talk"                          |
| - Invalid language code                                          |
| - Call not in answered state                                     |
| - Empty text string                                              |
| - Invalid SSML syntax                                            |
+------------------------------------------------------------------+

Digits Not Received

Problem: digits_receive action never captures input

Diagnostic Steps:
+------------------------------------------------------------------+
| 1. Check if any digits were captured                             |
|    GET /v1/activeflows/{id}/variables                            |
|    Look at: voipbin.call.digits                                  |
+------------------------------------------------------------------+
| 2. Check duration parameter                                      |
|    Is it long enough for user to respond?                        |
+------------------------------------------------------------------+
| 3. Check if previous audio completed                             |
|    digits_receive starts after previous action                   |
+------------------------------------------------------------------+

Configuration Check:
+------------------------------------------------------------------+
| {                                                                |
|   "type": "digits_receive",                                      |
|   "option": {                                                    |
|     "duration": 5000,    <- 5 seconds, is this enough?           |
|     "length": 1,         <- Expecting 1 digit                    |
|     "key": "#"           <- Terminate on # key                   |
|   }                                                              |
| }                                                                |
+------------------------------------------------------------------+

Common Causes:
+------------------------------------------------------------------+
| - Duration too short for user to respond                         |
| - Caller pressed wrong key (DTMF vs voice input)                 |
| - Phone doesn't support DTMF tones                               |
| - Audio codec incompatibility stripping DTMF                     |
+------------------------------------------------------------------+

Connect Action Failing

Problem: Connect action doesn't reach destination

Diagnostic Steps:
+------------------------------------------------------------------+
| 1. Check the outbound call status                                |
|    GET /v1/calls?reference_id={activeflow-id}                    |
|    Look for child calls created by connect                       |
+------------------------------------------------------------------+
| 2. Check destination format                                      |
|    Must be E.164 format (+15551234567)                           |
+------------------------------------------------------------------+
| 3. Check source number                                           |
|    Must be a number you own or have permissions to use           |
+------------------------------------------------------------------+

Common Causes:
+------------------------------------------------------------------+
| - Invalid destination phone number format                        |
| - Source number not in your account                              |
| - Destination is blocking calls                                  |
| - Carrier routing issue                                          |
| - Account doesn't have outbound calling enabled                  |
+------------------------------------------------------------------+

Variables Not Substituting

Problem: ${variable} appears literally in output instead of value

Diagnostic Steps:
+------------------------------------------------------------------+
| 1. Check variable exists                                         |
|    GET /v1/activeflows/{id}/variables                            |
+------------------------------------------------------------------+
| 2. Check variable name spelling                                  |
|    Variable names are case-sensitive                             |
+------------------------------------------------------------------+
| 3. Check syntax                                                  |
|    Must be ${name} not $name or {name}                           |
+------------------------------------------------------------------+

Example:
+------------------------------------------------------------------+
| Correct:   "${customer.name}"     -> "John Smith"                |
| Wrong:     "$customer.name"       -> "$customer.name"            |
| Wrong:     "{customer.name}"      -> "{customer.name}"           |
| Wrong:     "${Customer.Name}"     -> "" (wrong case)             |
+------------------------------------------------------------------+

Queue Join Not Working

Problem: Caller joins queue but never gets connected to agent

Diagnostic Steps:
+------------------------------------------------------------------+
| 1. Check queue status                                            |
|    GET /v1/queues/{queue-id}                                     |
|    Look at: agent count, online agents                           |
+------------------------------------------------------------------+
| 2. Check agent status                                            |
|    GET /v1/agents?queue_id={queue-id}                            |
|    Are agents online and available?                              |
+------------------------------------------------------------------+
| 3. Check queue configuration                                     |
|    Is timeout configured? Ring strategy?                         |
+------------------------------------------------------------------+

Common Causes:
+------------------------------------------------------------------+
| - No agents logged into queue                                    |
| - All agents are busy                                            |
| - Queue timeout expired                                          |
| - Agent ring timeout too short                                   |
| - Queue strategy misconfigured                                   |
+------------------------------------------------------------------+

Using Webhooks for Debugging

Set up webhooks to monitor flow execution in real-time:

Webhook Event Flow:

+------------------------------------------------------------------+
|                     Debug Webhook Setup                          |
+------------------------------------------------------------------+

1. Create a webhook endpoint to receive events
POST /v1/webhooks
{
  "name": "Debug Webhook",
  "url": "https://your-server.com/debug",
  "events": [
    "activeflow.created",
    "activeflow.updated",
    "activeflow.deleted",
    "call.progressing"
  ]
}

2. Events you'll receive during flow execution:

Flow starts:
{
  "type": "activeflow.created",
  "data": {
    "activeflow_id": "abc-123",
    "flow_id": "flow-456",
    "reference_id": "call-789"
  }
}

Each action execution:
{
  "type": "activeflow.updated",
  "data": {
    "activeflow_id": "abc-123",
    "current_action_id": "action-xyz",
    "status": "executing"
  }
}

Flow ends:
{
  "type": "activeflow.deleted",
  "data": {
    "activeflow_id": "abc-123",
    "reason": "completed"
  }
}

Testing Flows

Best practices for testing flows before production:

Testing Strategy:

+------------------------------------------------------------------+
|                     Development Testing                          |
+------------------------------------------------------------------+

1. API-Triggered Testing
+------------------------------------------------------------------+
| Create activeflow directly via API without a call:               |
|                                                                  |
| POST /v1/activeflows                                             |
| {                                                                |
|   "flow_id": "your-flow-id",                                     |
|   "reference_type": "api"                                        |
| }                                                                |
|                                                                  |
| This runs the flow without media actions (talk, play ignored)    |
| Useful for testing branching logic and webhooks                  |
+------------------------------------------------------------------+

2. Test Phone Number
+------------------------------------------------------------------+
| Reserve a dedicated test number for development                  |
| Attach test flows to this number                                 |
| Call it manually to verify behavior                              |
+------------------------------------------------------------------+

3. Webhook Logging
+------------------------------------------------------------------+
| Use webhook.site or similar service to capture webhooks          |
| Verify all expected events are fired                             |
| Check variable values in webhook payloads                        |
+------------------------------------------------------------------+
Test Checklist:

+------------------------------------------------------------------+
|                     Flow Test Checklist                          |
+------------------------------------------------------------------+

Basic Functionality:
[ ] Flow starts when call arrives
[ ] Answer action picks up call
[ ] Talk actions play audio
[ ] Flow completes without errors

Branching:
[ ] Each branch option routes correctly
[ ] Default branch catches invalid input
[ ] Retry loop works (goto with loop_count)

Variables:
[ ] Variables are set correctly
[ ] Variables substitute in talk text
[ ] Variables pass to webhooks

Error Cases:
[ ] Caller hangup is handled gracefully
[ ] Timeout on digits_receive works
[ ] Invalid input routes to default

Integrations:
[ ] Webhooks receive expected data
[ ] External APIs respond correctly
[ ] Queue routing works
[ ] Recording starts/stops properly

Debugging Webhook Integration

Common issues with webhook_send:

Webhook Send Debugging:

+------------------------------------------------------------------+
| Problem: Webhook not received                                    |
+------------------------------------------------------------------+

Check in your flow:
{
  "type": "webhook_send",
  "option": {
    "sync": false,           <- Async won't block flow
    "uri": "https://...",    <- Is URL accessible?
    "method": "POST",
    "data_type": "application/json",
    "data": "{...}"          <- Valid JSON?
  }
}

Common Issues:
+------------------------------------------------------------------+
| - URL not reachable from VoIPBIN servers                         |
| - Firewall blocking incoming requests                            |
| - SSL certificate issues (use valid cert)                        |
| - Invalid JSON in data field                                     |
| - Server returning error status code                             |
+------------------------------------------------------------------+

Debug Tips:
+------------------------------------------------------------------+
| 1. Test URL accessibility:                                       |
|    Can you curl the URL from a public server?                    |
|                                                                  |
| 2. Check SSL certificate:                                        |
|    Use valid, non-self-signed certificate                        |
|                                                                  |
| 3. Verify JSON syntax:                                           |
|    Run data through JSON validator                               |
|                                                                  |
| 4. Check server logs:                                            |
|    Is request arriving? What response code?                      |
+------------------------------------------------------------------+

Flow Execution Limits

Understanding and avoiding execution limits:

Execution Limits:

+------------------------------------------------------------------+
|                     Per-Cycle Limit: 1000                        |
+------------------------------------------------------------------+
| What counts: Each action executed in one cycle                   |
| Reset: When flow waits for async event (talk, connect, etc.)     |
|                                                                  |
| Trigger scenario:                                                |
| goto -> goto -> goto -> ... (1000 times) -> STOPPED              |
|                                                                  |
| Prevention:                                                      |
| - Always use loop_count on goto actions                          |
| - Add async actions (talk, sleep) in loops                       |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                     Total Execution Limit: 100                   |
+------------------------------------------------------------------+
| What counts: Each time flow resumes from async event             |
| Reset: Never (lifetime of activeflow)                            |
|                                                                  |
| Trigger scenario:                                                |
| A very long call with many interactions                          |
|                                                                  |
| Prevention:                                                      |
| - Design efficient flows                                         |
| - Avoid unnecessary action loops                                 |
| - Consider breaking into sub-flows                               |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                     On-Complete Chain Limit: 5                   |
+------------------------------------------------------------------+
| What counts: on_complete_flow_id triggers                        |
|                                                                  |
| Flow A -> Flow B -> Flow C -> Flow D -> Flow E -> STOPPED        |
|   0         1         2         3         4        5(blocked)    |
|                                                                  |
| Prevention:                                                      |
| - Limit on-complete chains                                       |
| - Use webhooks for post-call work instead                        |
+------------------------------------------------------------------+

Error Messages Reference

Common error messages and their meanings:

Error Reference:

+------------------------------------------------------------------+
| Error: "activeflow not found"                                    |
+------------------------------------------------------------------+
| Cause: Activeflow ID doesn't exist or was deleted                |
| Solution: Check ID, verify flow started successfully             |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
| Error: "flow not found"                                          |
+------------------------------------------------------------------+
| Cause: Flow definition ID doesn't exist                          |
| Solution: Verify flow_id, check if flow was deleted              |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
| Error: "action not found in flow"                                |
+------------------------------------------------------------------+
| Cause: goto/branch target_id doesn't exist in actions array      |
| Solution: Verify action IDs match between targets and actions    |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
| Error: "execution limit exceeded"                                |
+------------------------------------------------------------------+
| Cause: Hit 1000 per-cycle or 100 total execution limit           |
| Solution: Add loop_count to gotos, break up complex flows        |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
| Error: "invalid action type"                                     |
+------------------------------------------------------------------+
| Cause: Action type field has unknown value                       |
| Solution: Check spelling, use documented action types            |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
| Error: "variable not found"                                      |
+------------------------------------------------------------------+
| Cause: Referenced variable doesn't exist                         |
| Solution: Ensure variable is set before use, check spelling      |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
| Error: "call not in valid state for action"                      |
+------------------------------------------------------------------+
| Cause: Trying media action on non-answered call                  |
| Solution: Add answer action, verify call state                   |
+------------------------------------------------------------------+

Logging Best Practices

Add strategic webhooks for debugging:

Strategic Logging Points:

{
  "name": "Flow with Debug Logging",
  "actions": [
    {
      "type": "webhook_send",
      "option": {
        "uri": "https://your-api.com/debug",
        "method": "POST",
        "data_type": "application/json",
        "data": "{\"event\": \"flow_started\", \"call_id\": \"${voipbin.call.id}\"}"
      }
    },
    {
      "type": "answer"
    },
    {
      "type": "talk",
      "option": {
        "text": "Welcome. Press 1 or 2.",
        "language": "en-US"
      }
    },
    {
      "type": "digits_receive",
      "option": {
        "duration": 5000,
        "length": 1
      }
    },
    {
      "type": "webhook_send",
      "option": {
        "uri": "https://your-api.com/debug",
        "method": "POST",
        "data_type": "application/json",
        "data": "{\"event\": \"digits_received\", \"digits\": \"${voipbin.call.digits}\"}"
      }
    },
    {
      "type": "branch",
      "option": {
        "variable": "voipbin.call.digits",
        "target_ids": {
          "1": "option-1",
          "2": "option-2"
        }
      }
    },
    {
      "id": "option-1",
      "type": "webhook_send",
      "option": {
        "uri": "https://your-api.com/debug",
        "method": "POST",
        "data_type": "application/json",
        "data": "{\"event\": \"branch_selected\", \"branch\": \"option-1\"}"
      }
    }
  ]
}

Quick Diagnostic Commands

Common API calls for troubleshooting:

Diagnostic API Calls:

# List recent activeflows
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.voipbin.net/v1/activeflows?limit=10"

# Get specific activeflow
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.voipbin.net/v1/activeflows/{id}"

# Get activeflow variables
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.voipbin.net/v1/activeflows/{id}/variables"

# Find activeflow by call
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.voipbin.net/v1/activeflows?reference_id={call-id}"

# Get flow definition
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.voipbin.net/v1/flows/{flow-id}"

# Get call details
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.voipbin.net/v1/calls/{call-id}"

# List calls for a flow
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.voipbin.net/v1/calls?flow_id={flow-id}"

Flow Best Practices

This section covers design patterns, optimization techniques, and best practices for building maintainable and efficient flows.

Flow Design Principles

Keep Flows Focused

Principle: Single Responsibility

+------------------------------------------------------------------+
|                         BAD: Monolithic Flow                     |
+------------------------------------------------------------------+
| One giant flow that handles:                                     |
| - Language selection                                             |
| - Main menu                                                      |
| - Sales sub-menu                                                 |
| - Support sub-menu                                               |
| - Billing sub-menu                                               |
| - Queue logic                                                    |
| - Voicemail                                                      |
| - Survey                                                         |
|                                                                  |
| Problems:                                                        |
| - Hard to maintain                                               |
| - Hard to test                                                   |
| - Hard to reuse components                                       |
| - Changes affect everything                                      |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                        GOOD: Modular Flows                       |
+------------------------------------------------------------------+
|                                                                  |
| Main Router Flow                                                 |
|   └── fetch_flow: Language Selection                             |
|         └── fetch_flow: Main Menu                                |
|               ├── fetch_flow: Sales Menu                         |
|               ├── fetch_flow: Support Menu                       |
|               └── fetch_flow: Billing Menu                       |
|                                                                  |
| Shared Flows:                                                    |
|   - Queue Wait Flow (reused by all menus)                        |
|   - Voicemail Flow (reused for after-hours)                      |
|   - Survey Flow (attached via on_complete_flow_id)               |
|                                                                  |
| Benefits:                                                        |
| - Each flow has one job                                          |
| - Easy to test individually                                      |
| - Reusable components                                            |
| - Changes are localized                                          |
+------------------------------------------------------------------+

Use Meaningful Action IDs

Action ID Best Practices:

+------------------------------------------------------------------+
|                            BAD                                   |
+------------------------------------------------------------------+
| {                                                                |
|   "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",                  |
|   "type": "talk",                                                |
|   ...                                                            |
| }                                                                |
|                                                                  |
| Debugging nightmare:                                             |
| "Flow stopped at action a1b2c3d4-e5f6-7890-abcd-ef1234567890"    |
| What does this action do?                                        |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                           GOOD                                   |
+------------------------------------------------------------------+
| {                                                                |
|   "id": "welcome-greeting",                                      |
|   "type": "talk",                                                |
|   ...                                                            |
| }                                                                |
|                                                                  |
| {                                                                |
|   "id": "main-menu-branch",                                      |
|   "type": "branch",                                              |
|   ...                                                            |
| }                                                                |
|                                                                  |
| {                                                                |
|   "id": "invalid-input-retry",                                   |
|   "type": "goto",                                                |
|   ...                                                            |
| }                                                                |
|                                                                  |
| Debugging is clear:                                              |
| "Flow stopped at action main-menu-branch"                        |
| Immediately know where and what                                  |
+------------------------------------------------------------------+

Naming Convention:
+------------------------------------------------------------------+
| Format: {context}-{purpose}                                      |
|                                                                  |
| Examples:                                                        |
| - welcome-greeting                                               |
| - menu-input-receive                                             |
| - sales-branch                                                   |
| - invalid-retry-loop                                             |
| - after-hours-voicemail                                          |
+------------------------------------------------------------------+

Always Include Default Branches

Branch Best Practice:

+------------------------------------------------------------------+
|                            BAD                                   |
+------------------------------------------------------------------+
| {                                                                |
|   "type": "branch",                                              |
|   "option": {                                                    |
|     "variable": "voipbin.call.digits",                           |
|     "target_ids": {                                              |
|       "1": "option-1",                                           |
|       "2": "option-2"                                            |
|     }                                                            |
|   }                                                              |
| }                                                                |
|                                                                  |
| Problem: What happens if user presses 3, 4, 5, etc.?             |
| Flow falls through to next action unexpectedly                   |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                           GOOD                                   |
+------------------------------------------------------------------+
| {                                                                |
|   "type": "branch",                                              |
|   "option": {                                                    |
|     "variable": "voipbin.call.digits",                           |
|     "default_target_id": "invalid-input-handler",                |
|     "target_ids": {                                              |
|       "1": "option-1",                                           |
|       "2": "option-2"                                            |
|     }                                                            |
|   }                                                              |
| }                                                                |
|                                                                  |
| All unexpected inputs are caught and handled                     |
+------------------------------------------------------------------+

Use Loop Counts

Goto Best Practice:

+------------------------------------------------------------------+
|                            BAD                                   |
+------------------------------------------------------------------+
| {                                                                |
|   "type": "goto",                                                |
|   "option": {                                                    |
|     "target_id": "menu-start"                                    |
|   }                                                              |
| }                                                                |
|                                                                  |
| Problem: Infinite loop possible                                  |
| User keeps entering invalid input forever                        |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                           GOOD                                   |
+------------------------------------------------------------------+
| {                                                                |
|   "type": "goto",                                                |
|   "option": {                                                    |
|     "target_id": "menu-start",                                   |
|     "loop_count": 3                                              |
|   }                                                              |
| }                                                                |
|                                                                  |
| After 3 attempts, flow continues past goto                       |
| Add a "too many attempts" handler after the goto                 |
+------------------------------------------------------------------+

Performance Optimization

Minimize Webhook Calls

Webhook Optimization:

+------------------------------------------------------------------+
|                            BAD                                   |
+------------------------------------------------------------------+
| Every action sends a webhook:                                    |
|                                                                  |
| answer -> webhook -> talk -> webhook -> digits -> webhook        |
|                                                                  |
| Problems:                                                        |
| - Slows down flow execution                                      |
| - High load on your server                                       |
| - Increased latency for caller                                   |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                           GOOD                                   |
+------------------------------------------------------------------+
| Strategic webhooks at key points:                                |
|                                                                  |
| answer -> talk -> digits -> branch -> webhook (with all data)    |
|                                                                  |
| Batch data in a single webhook:                                  |
| {                                                                |
|   "call_id": "${voipbin.call.id}",                               |
|   "caller": "${voipbin.call.source.target}",                     |
|   "selection": "${voipbin.call.digits}",                         |
|   "timestamp": "${voipbin.activeflow.tm_create}"                 |
| }                                                                |
+------------------------------------------------------------------+

Use Async Webhooks When Possible

Sync vs Async Webhooks:

+------------------------------------------------------------------+
|                     Sync (sync: true)                            |
+------------------------------------------------------------------+
| Flow waits for response before continuing                        |
|                                                                  |
| Use when:                                                        |
| - You need data from the response                                |
| - Response sets variables for branching                          |
| - Order of operations matters                                    |
|                                                                  |
| Example: Customer lookup before greeting                         |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                    Async (sync: false)                           |
+------------------------------------------------------------------+
| Flow continues immediately, doesn't wait                         |
|                                                                  |
| Use when:                                                        |
| - Just logging/notification                                      |
| - Response data not needed                                       |
| - Background processing (analytics, etc.)                        |
|                                                                  |
| Example: Logging call events for analytics                       |
+------------------------------------------------------------------+

Optimize Audio Prompts

Audio Optimization:

+------------------------------------------------------------------+
|                     TTS vs Pre-recorded                          |
+------------------------------------------------------------------+

Use TTS (talk action) when:
+------------------------------------------------------------------+
| - Content is dynamic (names, numbers, dates)                     |
| - Frequent text changes                                          |
| - Multiple languages needed                                      |
| - Prototyping/development                                        |
+------------------------------------------------------------------+

Use Pre-recorded (play action) when:
+------------------------------------------------------------------+
| - Content is static                                              |
| - Professional voice quality needed                              |
| - Brand voice consistency important                              |
| - High-volume production traffic                                 |
+------------------------------------------------------------------+

Performance Comparison:
+------------------------------------------------------------------+
| TTS: ~100-300ms generation time per phrase                       |
| Pre-recorded: ~50ms to start playback                            |
+------------------------------------------------------------------+

Keep Variable Names Short

Variable Naming:

+------------------------------------------------------------------+
|                            BAD                                   |
+------------------------------------------------------------------+
| ${customer_information.primary_contact.phone_number.country_code}|
|                                                                  |
| Problems:                                                        |
| - Hard to read in JSON                                           |
| - More data in database                                          |
| - Prone to typos                                                 |
+------------------------------------------------------------------+

+------------------------------------------------------------------+
|                           GOOD                                   |
+------------------------------------------------------------------+
| ${customer.phone}                                                |
| ${customer.country}                                              |
|                                                                  |
| Or use namespaces:                                               |
| ${cust.phone}                                                    |
| ${cust.tier}                                                     |
+------------------------------------------------------------------+

Error Handling Patterns

Graceful Degradation

Fallback Pattern:

+------------------------------------------------------------------+
|                     Handle Service Failures                      |
+------------------------------------------------------------------+

{
  "name": "Resilient Flow",
  "actions": [
    {
      "type": "answer"
    },
    {
      "id": "try-personalization",
      "type": "webhook_send",
      "option": {
        "sync": true,
        "uri": "https://your-api.com/customer",
        "method": "POST",
        "data_type": "application/json",
        "data": "{\"phone\": \"${voipbin.call.source.target}\"}"
      }
    },
    {
      "type": "condition_variable",
      "option": {
        "condition": "!=",
        "variable": "customer.name",
        "value_type": "string",
        "value_string": "",
        "false_target_id": "generic-greeting"
      }
    },
    {
      "id": "personalized-greeting",
      "type": "talk",
      "option": {
        "text": "Hello ${customer.name}, welcome back.",
        "language": "en-US"
      }
    },
    {
      "type": "goto",
      "option": {
        "target_id": "main-menu"
      }
    },
    {
      "id": "generic-greeting",
      "type": "talk",
      "option": {
        "text": "Hello, welcome to our service.",
        "language": "en-US"
      }
    },
    {
      "id": "main-menu",
      "type": "talk",
      "option": {
        "text": "Press 1 for sales, 2 for support.",
        "language": "en-US"
      }
    }
  ]
}

Timeout Handling

Input Timeout Pattern:

+------------------------------------------------------------------+
|                     Handle No Response                           |
+------------------------------------------------------------------+

{
  "actions": [
    {
      "id": "prompt",
      "type": "talk",
      "option": {
        "text": "Press 1 or 2.",
        "language": "en-US"
      }
    },
    {
      "type": "digits_receive",
      "option": {
        "duration": 5000,
        "length": 1
      }
    },
    {
      "type": "condition_variable",
      "option": {
        "condition": "!=",
        "variable": "voipbin.call.digits",
        "value_type": "string",
        "value_string": "",
        "false_target_id": "no-input"
      }
    },
    {
      "type": "branch",
      "option": {
        "variable": "voipbin.call.digits",
        "default_target_id": "invalid-input",
        "target_ids": {
          "1": "option-1",
          "2": "option-2"
        }
      }
    },
    {
      "id": "no-input",
      "type": "talk",
      "option": {
        "text": "I didn't receive any input.",
        "language": "en-US"
      }
    },
    {
      "type": "goto",
      "option": {
        "target_id": "prompt",
        "loop_count": 2
      }
    },
    {
      "type": "talk",
      "option": {
        "text": "Goodbye.",
        "language": "en-US"
      }
    },
    {
      "type": "hangup"
    },
    {
      "id": "invalid-input",
      "type": "talk",
      "option": {
        "text": "Invalid selection.",
        "language": "en-US"
      }
    },
    {
      "type": "goto",
      "option": {
        "target_id": "prompt",
        "loop_count": 2
      }
    }
  ]
}

Maintainability

Document Your Flows

Flow Documentation:

+------------------------------------------------------------------+
|                     Use Name and Detail Fields                   |
+------------------------------------------------------------------+

{
  "name": "Main IVR Menu - English",
  "detail": "Primary entry point for English callers. Routes to Sales, Support, or Billing queues. Uses business hours check. Last updated: 2024-01-15",
  "actions": [...]
}

Naming Convention:
+------------------------------------------------------------------+
| Format: {Function} - {Context}                                   |
|                                                                  |
| Examples:                                                        |
| - "Main IVR Menu - English"                                      |
| - "Support Queue Wait Flow"                                      |
| - "After Hours Voicemail"                                        |
| - "Post-Call Survey - Premium Customers"                         |
+------------------------------------------------------------------+

Version Your Flows

Versioning Strategy:

+------------------------------------------------------------------+
|                     Flow Versioning                              |
+------------------------------------------------------------------+

Option 1: Include version in name
{
  "name": "Main IVR v2.1",
  "detail": "Version 2.1 - Added Spanish language option"
}

Option 2: Keep multiple flow versions
+------------------------------------------------------------------+
| Production: "main-ivr-prod"     <- Stable, live traffic          |
| Staging:    "main-ivr-staging"  <- Testing new features          |
| Dev:        "main-ivr-dev"      <- Development/experiments       |
+------------------------------------------------------------------+

Promotion workflow:
1. Develop in dev flow
2. Test in staging flow
3. Copy to production flow when ready

Test in Isolation

Testing Approach:

+------------------------------------------------------------------+
|                     Modular Testing                              |
+------------------------------------------------------------------+

Each sub-flow can be tested independently:

1. Language Selection Flow
   - Test: All language options work
   - Test: Default fallback works

2. Main Menu Flow
   - Test: All branch options route correctly
   - Test: Invalid input handling
   - Test: Timeout handling

3. Support Queue Flow
   - Test: Queue join works
   - Test: Wait music plays
   - Test: Timeout routes to voicemail

4. Voicemail Flow
   - Test: Recording starts
   - Test: Recording stops on timeout
   - Test: Recording stops on key press

Security Best Practices

Validate External Data

Input Validation:

+------------------------------------------------------------------+
|                     Validate Webhook Responses                   |
+------------------------------------------------------------------+

When using data from webhook_send responses:

BAD:
{
  "type": "talk",
  "option": {
    "text": "Calling ${customer.phone}",   <- Could be anything!
    "language": "en-US"
  }
}

GOOD:
{
  "type": "condition_variable",
  "option": {
    "condition": "!=",
    "variable": "customer.phone",
    "value_type": "string",
    "value_string": "",
    "false_target_id": "no-phone-error"
  }
}
... then use customer.phone

Protect Sensitive Data

Data Protection:

+------------------------------------------------------------------+
|                     Sensitive Information                        |
+------------------------------------------------------------------+

Don't log sensitive data in webhooks:

BAD:
{
  "type": "webhook_send",
  "option": {
    "data": "{\"credit_card\": \"${customer.card}\"}"
  }
}

GOOD:
{
  "type": "webhook_send",
  "option": {
    "data": "{\"customer_id\": \"${customer.id}\", \"action\": \"payment_attempt\"}"
  }
}

Look up sensitive data server-side using customer_id

Rate Limiting Awareness

Rate Limiting:

+------------------------------------------------------------------+
|                     API Rate Limits                              |
+------------------------------------------------------------------+

Be aware of limits on:
- Webhook requests to your server
- VoIPBIN API calls
- TTS generation requests

Design flows to minimize API calls:
+------------------------------------------------------------------+
| - Batch data in single webhooks                                  |
| - Cache customer data for session duration                       |
| - Use variables instead of repeated lookups                      |
+------------------------------------------------------------------+

Checklist: Flow Review

Before deploying a new flow, verify:

Pre-Deployment Checklist:

Structure:
[ ] All action IDs are meaningful and unique
[ ] All branch actions have default_target_id
[ ] All goto actions have loop_count
[ ] Flow name and detail are descriptive
[ ] Modular design (sub-flows where appropriate)

Error Handling:
[ ] Invalid input is handled
[ ] Timeouts are handled
[ ] Service failures have fallbacks
[ ] Caller hangup is considered

Performance:
[ ] Webhook calls are minimized
[ ] Async webhooks used where possible
[ ] No unnecessary loops
[ ] Variables are concise

Security:
[ ] No sensitive data in webhooks
[ ] External data is validated
[ ] Recording consent is obtained (if required)

Testing:
[ ] All branches tested
[ ] Timeout scenarios tested
[ ] Error scenarios tested
[ ] End-to-end call tested

Documentation:
[ ] Flow name describes purpose
[ ] Flow detail includes version/date
[ ] Complex logic is commented (in detail field)

Activeflow

Overview

The activeflow is a dynamic entity within the VoIPBIN system that plays a vital role in representing the real-time state of a registered flow. As the flow is executed, it generates an activeflow, which contains an action cursor and relevant status information. This activeflow serves as a control interface, providing efficient management and flexibility during flow execution.

In essence, the activeflow concept is a powerful tool that facilitates the smooth and flexible execution of registered flows. Its dynamic nature allows for real-time updates, ensuring that users can monitor and manage the flow execution efficiently.

By providing real-time status updates and a flexible control interface, the activeflow becomes a valuable tool for businesses to efficiently manage complex workflows and automate their critical processes. The stop functionality adds an extra layer of control and adaptability, allowing users to make informed decisions and optimize their flow executions as required.

Flow vs ActiveFlow

Understanding the difference between a Flow and an ActiveFlow is essential for working with VoIPBIN.

+-------------------------------------------------------------------------+
|                        Flow vs ActiveFlow                                |
+-------------------------------------------------------------------------+

Flow (Template)                         ActiveFlow (Running Instance)
+-------------------------+            +---------------------------------+
| o Static definition     |            | o Dynamic execution state       |
| o Reusable template     |            | o One-time instance             |
| o Stored in database    |            | o Tracks current position       |
| o No execution state    |            | o Contains variables            |
|                         |            | o Linked to call/conversation   |
+-------------------------+            +---------------------------------+
           |                                        ^
           |     When triggered                     |
           +----------------------------------------+
                    Creates

Analogy: A Flow is like a recipe book. An ActiveFlow is like actually cooking that recipe - you track which step you’re on, what ingredients you’ve used, and the current state of the dish.

Flow (Recipe Book)                    ActiveFlow (Cooking Session)
+--------------------+               +--------------------------------+
| Step 1: Answer     |               | Step 1: Answer (done)          |
| Step 2: Talk       |   ------>     | Step 2: Talk <-- current       |
| Step 3: Branch     |               | Step 3: Branch (pending)       |
| Step 4: Hangup     |               | Step 4: Hangup (pending)       |
+--------------------+               |                                |
                                     | Variables:                     |
                                     |   caller_id: "+1234567890"     |
                                     |   digits: "2"                  |
                                     +--------------------------------+

ActiveFlow States

An activeflow has two possible states during its lifecycle:

+------------+                              +------------+
|  running   |----------------------------->|   ended    |
+------------+                              +------------+
      |                                            |
      |                                            |
Actions executing                           Final state
Cursor moving                               No more changes
Variables updating                          History preserved

Status

What it means

running

The activeflow is actively executing actions. The cursor is moving through the flow, and the state can change at any time.

ended

The activeflow has completed. No further execution will occur. The executed_actions history is preserved for review.

Execution

The activeflow’s significance lies in its ability to manage complex workflows and automate business processes effectively. As the flow progresses through its various stages, the activeflow dynamically represents its current state. This representation provides valuable insights into the flow’s progress and status, enabling efficient and informed management of its execution.

+-----------------------------------------------------------------------+
|                     ActiveFlow Execution Model                         |
+-----------------------------------------------------------------------+

Incoming Call           ActiveFlow Created            Execution Begins
     |                        |                            |
     v                        v                            v
+---------+              +---------+                 +-------------+
|  CALL   |------------->|  NEW    |---------------->|  RUNNING    |
| arrives |              | instance|                 |  actions    |
+---------+              +---------+                 +------+------+
                              |                            |
                              |                            v
                              |                      +-----------+
                              |  Variables set:      |  cursor   |
                              |  o reference_type    |  moves    |--+
                              |  o reference_id      +-----------+  |
                              |  o customer_id                      |
                              |  o flow_id                          |
                              +-------------------------------------+
_images/activeflow_overview_execution.png

How the Cursor Works

The activeflow maintains a “cursor” that tracks the current position in the flow:

Action Array:
+---------+   +---------+   +---------+   +---------+   +---------+
| answer  |   |  talk   |   | digits  |   | branch  |   | hangup  |
| index:0 |   | index:1 |   | index:2 |   | index:3 |   | index:4 |
+---------+   +---------+   +---------+   +---------+   +---------+
                   ^
                   |
                current_action (cursor is here)

Cursor Movement Rules:

  1. Sequential: By default, cursor moves to the next action in array order

  2. Jump: Actions like goto and branch can jump to any action by ID

  3. Nested: Some actions push a new stack (queue_join, ai_talk), cursor enters nested stack

  4. Return: When nested stack completes, cursor returns to original position

Stack-Based Execution

ActiveFlows use a stack-based model to handle nested flows (like queue wait flows or AI conversations):

+-----------------------------------------------------------------------+
|                       Stack-Based Execution                            |
+-----------------------------------------------------------------------+

Main Stack                          Nested Stack (from queue_join)
+---------------------+            +---------------------------------+
| 1. answer           |            |                                 |
| 2. queue_join ======+============> wait_flow actions:              |
| 3. talk "connected" |            |   o talk "Please hold..."       |
| 4. hangup           |            |   o play music.mp3              |
+---------------------+            |   o (loops until agent answers) |
       ^                           +---------------------------------+
       |                                         |
       |    When agent answers,                  |
       +-----------------------------------------+
             return to main stack

Stack Map Structure:

The activeflow maintains a stack_map that tracks all stacks:

stack_map: {
    "main": {
        actions: [...],
        current_index: 1,
        return_stack: null,
        return_action: null
    },
    "queue-wait-abc123": {
        actions: [...wait flow actions...],
        current_index: 0,
        return_stack: "main",
        return_action: "talk connected"
    }
}

Reference Types

Each activeflow is linked to a reference - the entity that triggered it:

+--------------------------------------------------------------------+
|                    ActiveFlow Reference Types                       |
+--------------------------------------------------------------------+

Reference Type

When it’s used

call

Flow was triggered by an incoming or outgoing call

conversation

Flow was triggered by a message in a conversation

api

Flow was triggered directly via API call

campaign

Flow was triggered by an outbound campaign

transcribe

Flow was triggered for transcription processing

recording

Flow was triggered for recording processing

ai

Flow was triggered for AI processing

Reference Impact on Actions:

The reference type determines which actions are available:

Reference: call                     Reference: api
+-------------------------+        +-------------------------+
| (check) answer          |        | (x) answer (no call)    |
| (check) talk            |        | (x) talk (no media)     |
| (check) digits_receive  |        | (x) digits_receive      |
| (check) recording_start |        | (x) recording_start     |
| (check) message_send    |        | (check) message_send    |
| (check) email_send      |        | (check) email_send      |
| (check) webhook_send    |        | (check) webhook_send    |
| (check) variable_set    |        | (check) variable_set    |
+-------------------------+        +-------------------------+

When an action is not available for the reference type, it is skipped and execution continues to the next action.

Status and Control interface

The activeflow includes essential status information that allows users to monitor the flow’s progress closely. This information encompasses details about the activeflow’s current state, including completed and pending actions. Additionally, the activeflow offers a control interface that empowers users to manage the execution process. This interface enables actions such as stopping the activeflow at any point and modifying its configuration or parameters as needed.

Control API Endpoints:

+-----------------------------------------------------------------------+
|                    ActiveFlow Control Interface                        |
+-----------------------------------------------------------------------+

GET /v1/activeflows/{id}
+-- View current state
+-- See current_action
+-- Review executed_actions
+-- Check variables

POST /v1/activeflows/{id}/execute
+-- Resume a blocked flow
+-- Push new actions
+-- Continue execution

POST /v1/activeflows/{id}/stop
+-- Immediately stop execution
+-- Status changes to "ended"
+-- Triggers on_complete_flow if set

Activeflow Lifecycle

The activeflow executes the actions until one of the following conditions is met:

+-----------------------------------------------------------------------+
|                  ActiveFlow Termination Conditions                     |
+-----------------------------------------------------------------------+

Condition 1: End of Actions
+---+   +---+   +---+   +---------+
| 1 |-->| 2 |-->| 3 |-->|  DONE   |  -> Status: ended
+---+   +---+   +---+   +---------+

Condition 2: Stop Action
+---+   +---+   +------+
| 1 |-->| 2 |-->| stop |  -> Status: ended
+---+   +---+   +------+

Condition 3: Reference Ends (e.g., call hangup)
+---+   +---+   +---+
| 1 |-->| 2 |-->| X |  -> Call hangup -> Status: ended
+---+   +---+   +---+

Condition 4: API Stop Request
+---+   +---+   +---+
| 1 |-->| 2 |-->| 3 |  + POST /stop -> Status: ended
+---+   +---+   +---+
  • Main Service Type Completion: The activeflow continues executing flow actions until the primary service type is completed. For instance, in the case of a call service, actions will be executed until the call is hung up.

  • Stop Action Execution: Execution ceases if an action with the type “stop” is encountered in the flow.

  • User-Initiated Interruption: Users can actively interrupt their activeflow by sending a POST request to the endpoint: https://api.voipbin.net/v1/activeflows/<activeflow-id>/stop.

Variable Management

Each activeflow maintains its own set of variables that persist throughout execution:

+-----------------------------------------------------------------------+
|                    ActiveFlow Variable Storage                         |
+-----------------------------------------------------------------------+

ActiveFlow: abc-123-def
+-----------------------------------------------------------------------+
| Variables Map                                                          |
+---------------------------------+-------------------------------------+
| voipbin.activeflow.id           | "abc-123-def"                     |
| voipbin.activeflow.reference_id | "call-456"                        |
| voipbin.call.digits             | "2"                               |
| voipbin.call.caller_id          | "+14155551234"                    |
| customer.language               | "en-US"                           |
| customer.tier                   | "premium"                         |
+---------------------------------+-------------------------------------+

Variable Lifecycle:

1. Created when activeflow starts (built-in variables)
      |
      v
2. Updated by actions (digits_receive, variable_set, fetch)
      |
      v
3. Read by actions (branch, condition_variable, talk with ${var})
      |
      v
4. Inherited by on_complete_flow (if configured)
      |
      v
5. Preserved in database when activeflow ends

Executed Actions

Within the CPaaS environment, flows can be complex, incorporating various service types such as call, SMS, chat, and more. Handling history logs for these diverse services requires a structured approach.

VoIPBIN simplifies the tracking of executed actions by providing a comprehensive history log within the activeflow. Unlike traditional telephony services with straightforward flows, CPaaS services demand a more flexible approach due to their diverse nature.

In VoIPBIN, each action in the activeflow defines a distinct step in the service’s behavior. This ensures clarity in tracking the sequence of actions performed.

+-----------------------------------------------------------------------+
|                    Executed Actions History                            |
+-----------------------------------------------------------------------+

Time ---------------------------------------------------------------------->

+----------+   +----------+   +----------+   +----------+
| answer   |-->| talk     |-->| connect  |-->| message  |
| 10:00:01 |   | 10:00:02 |   | 10:00:15 |   | 10:00:45 |
+----------+   +----------+   +----------+   +----------+
     v              v              v              v
+---------------------------------------------------------+
|              executed_actions array                      |
+---------------------------------------------------------+
{
    "executed_actions": [
        {
            "type": "connect",
            "option": {
                "source": {
                    "type": "tel",
                    "target": "+15559876543"
                },
                "destinations": [
                    {
                        "type": "tel",
                        "target": "+15551112222"
                    }
                ]
            }
        },
        {
            "id": "605f5650-ba92-4dcd-bdac-91fcf6260939",
            "next_id": "00000000-0000-0000-0000-000000000000",
            "type": "message_send",
            "option": {
                "text": "hello, this is a test message.",
                "source": {
                    "type": "tel",
                    "target": "+15559876543"
                },
                "destinations": [
                    {
                        "type": "tel",
                        "target": "+31616818985"
                    }
                ]
            }
        }
    ]
}

With the detailed information provided in the executed_actions array, customers can easily review and understand the history logs of their CPaaS services.

On Complete Flow

When an activeflow ends, it can trigger another flow automatically:

+-----------------------------------------------------------------------+
|                    On Complete Flow Chain                              |
+-----------------------------------------------------------------------+

ActiveFlow A                             ActiveFlow B
+-------------------------+             +-------------------------+
| on_complete_flow_id: B  |             | Created automatically   |
|                         |             |                         |
| status: "ended"         |------------>| status: "running"       |
|                         |             |                         |
| Variables:              |  inherited  | Variables:              |
|   call_id: "123"        |------------>|   call_id: "123"        |
|   recording_id: "456"   |             |   recording_id: "456"   |
+-------------------------+             +-------------------------+

Key Behaviors:

  • New activeflow is created with a new ID

  • Variables are copied from parent to child

  • reference_activeflow_id is set to parent’s ID (tracks the chain)

  • Maximum chain depth is 5 (prevents infinite loops)

Error Handling

ActiveFlows handle errors gracefully to ensure reliable execution:

+-----------------------------------------------------------------------+
|                    Error Handling Scenarios                            |
+-----------------------------------------------------------------------+

Scenario: Action fails
+---+   +---+   +-----+   +---+
| 1 |-->| 2 |-->| ERR |-->| 4 |  (skip failed action, continue)
+---+   +---+   +-----+   +---+

Scenario: Critical failure
+---+   +---+   +-----+
| 1 |-->| 2 |-->| ERR |  -> Status: ended (flow stops)
+---+   +---+   +-----+

Scenario: Max iterations exceeded
+---+   +---+   +---+   +---+
| 1 |<->| 2 |<->| 3 |<->| X |  -> Infinite loop detected, stop
+---+   +---+   +---+   +---+

Safety Limits:

Limit

Value

Purpose

Max iterations per cycle

1000

Prevents infinite loops in goto/branch

Max total execute calls

100

Prevents runaway execution

Max on_complete chain depth

5

Prevents infinite flow chaining

Common Use Cases

Use Case 1: IVR Menu with History Tracking

+--------------------------------------------------------------------+
| executed_actions shows the complete journey:                        |
|                                                                     |
| 1. answer --> 2. talk "Welcome" --> 3. digits "2" --> 4. branch    |
|      --> 5. talk "Support" --> 6. queue_join --> 7. connect agent  |
+--------------------------------------------------------------------+

Use Case 2: Post-Call Processing

Call Flow ActiveFlow                After Call Work ActiveFlow
+----------------------+           +------------------------------+
| answer               |           | fetch recording              |
| talk                 |           | ai_summarize                 |
| connect to agent     |           | webhook_send summary         |
| (call ends)          |---------->| email_send transcript        |
|                      |           |                              |
| on_complete: "acw"   |           | Inherits: recording_id,      |
+----------------------+           |           call_id            |
                                   +------------------------------+

Use Case 3: Debugging Flow Execution

GET /v1/activeflows/{id}

Response shows:
{
    "status": "running",
    "current_action": {
        "type": "digits_receive",
        "option": { "duration": 5000 }
    },
    "executed_actions": [
        { "type": "answer", ... },
        { "type": "talk", "option": { "text": "Welcome" } }
    ],
    "variables": {
        "voipbin.call.caller_id": "+14155551234"
    }
}

-> You can see exactly where the flow is and what has happened

Activeflow

Activeflow

{
    "id": "<string>",
    "customer_id": "<string>",
    "flow_id": "<string>",
    "status": "<string>",
    "reference_type": "<string>",
    "reference_id": "<string>",
    "current_action": {
        ...
    },
    "forward_action_id": "<string>",
    "tm_create": "<string>",
    "tm_update": "<string>",
    "tm_delete": "<string>"
}
  • id: Activeflow’s ID.

  • customer_id: Customer’s ID.

  • flow_id: Flow’s ID.

  • status: Activeflow’s status. See detail here.

  • reference_type: Represent which resource started activeflow.

  • reference_id: Referenced type’s ID.

  • current_action: Currently running action on this activeflow. See detail here.

  • forward_action_id: Forward action id.

Example

{
    "id": "6f18ae1c-ddf8-413b-9572-ad30574604ef",
    "customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
    "flow_id": "93993ae1-0408-4639-ad5f-1288aa8d4325",
    "status": "ended",
    "reference_type": "call",
    "reference_id": "fd581a20-2606-47fd-a7e8-6bba7c294170",
    "current_action": {
        "id": "93ebcadb-ecae-4291-8d49-ca81a926b8b3",
        "next_id": "00000000-0000-0000-0000-000000000000",
        "type": "digits_receive",
        "option": {
            "length": 1,
            "duration": 5000
        }
    },
    "forward_action_id": "00000000-0000-0000-0000-000000000000",
    "tm_create": "2023-04-06 14:53:12.569073",
    "tm_update": "2023-04-06 14:54:24.652558",
    "tm_delete": "9999-01-01 00:00:00.000000"
}

Status

Activeflow’s status.

Type

Description

EMPTY

None

running

Activeflow is running.

ended

Activeflow has stopped.

Reference type

The resource type that triggered the activeflow execution.

Type

Description

call

Incoming or outgoing call triggered the flow.

message

Incoming SMS/MMS message triggered the flow.

api

Flow started via API call.

campaign

Outbound campaign triggered the flow.

transcribe

Transcription service triggered the flow.

recording

Recording completion triggered the flow.

ai

AI service triggered the flow.

Tutorial

Get activeflow list

Getting a list of activeflows.

$ curl -k --location --request GET 'https://api.voipbin.net/v1.0/activeflows?token=<YOUR_AUTH_TOKEN>'

{
    "result": [
        {
            "id": "6f18ae1c-ddf8-413b-9572-ad30574604ef",
            "customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
            "flow_id": "93993ae1-0408-4639-ad5f-1288aa8d4325",
            "status": "ended",
            "reference_type": "call",
            "reference_id": "fd581a20-2606-47fd-a7e8-6bba7c294170",
            "current_action": {
                "id": "93ebcadb-ecae-4291-8d49-ca81a926b8b3",
                "next_id": "00000000-0000-0000-0000-000000000000",
                "type": "digits_receive",
                "option": {
                    "length": 1,
                    "duration": 5000
                }
            },
            "forward_action_id": "00000000-0000-0000-0000-000000000000",
            "tm_create": "2023-04-06 14:53:12.569073",
            "tm_update": "2023-04-06 14:54:24.652558",
            "tm_delete": "9999-01-01 00:00:00.000000"
        },
        ...
    ],
    "next_page_token": "2023-04-02 13:43:30.576077"
}

Stop activeflow

Stop the activeflow.

$ curl --location --request POST 'https://api.voipbin.net/v1.0/activeflows/1cb0566c-6aa5-45fd-beb7-e71a968075ea/stop?token=<YOUR_AUTH_TOKEN>'

{
    "id": "1cb0566c-6aa5-45fd-beb7-e71a968075ea",
    "customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
    "flow_id": "93993ae1-0408-4639-ad5f-1288aa8d4325",
    "status": "ended",
    "reference_type": "call",
    "reference_id": "cd40b5f5-dafc-43e6-9b70-38edc1155a0f",
    "current_action": {
        "id": "f9720d64-a8a8-11ed-8853-3f29a447aac1",
        "next_id": "00000000-0000-0000-0000-000000000000",
        "type": "talk",
        "option": {
            "text": "Hello. Welcome to the VoIPBIN service. Please select a service. For simple talk, press 1. For simple transcribe, press 2. For queue join, press 3. For voicemail, press 4. For conference, press 5. For chatbot talk, press 6. To contact support, press 0.",
            "language": "en-US",
            "digits_handle": "next"
        }
    },
    "forward_action_id": "00000000-0000-0000-0000-000000000000",
    "tm_create": "2023-04-07 17:23:33.665475",
    "tm_update": "2023-04-07 17:23:52.561527",
    "tm_delete": "9999-01-01 00:00:00.000000"
}